diff --git a/blog/src/_data/media.json b/blog/src/_data/media.json index ae3ff34c6..adcd7e740 100644 --- a/blog/src/_data/media.json +++ b/blog/src/_data/media.json @@ -4610,5 +4610,16 @@ "status": "ready" }, "inline": {} + }, + "claude-haiku-5-5": { + "title": "Claude Haiku 5.5: price, benchmarks and where it fits", + "category": "concepts", + "hero": { + "file": "assets/media/claude-haiku-5-5/hero.png", + "alt": "Title card on white. Claude Haiku 5.5 in large ink type over a yellow underline, a Concepts kicker, the line Checked 8 Oct 2026, and a row of coloured dominoes part way through falling", + "prompt": "Still of the hero scene in assets/media/claude-haiku-5-5/motion.js.", + "status": "ready" + }, + "inline": {} } } diff --git a/blog/src/assets/media/claude-haiku-5-5/cups.png b/blog/src/assets/media/claude-haiku-5-5/cups.png new file mode 100644 index 000000000..51af3d5ba Binary files /dev/null and b/blog/src/assets/media/claude-haiku-5-5/cups.png differ diff --git a/blog/src/assets/media/claude-haiku-5-5/hero.png b/blog/src/assets/media/claude-haiku-5-5/hero.png new file mode 100644 index 000000000..8b7491b0e Binary files /dev/null and b/blog/src/assets/media/claude-haiku-5-5/hero.png differ diff --git a/blog/src/assets/media/claude-haiku-5-5/motion.css b/blog/src/assets/media/claude-haiku-5-5/motion.css new file mode 100644 index 000000000..a0101a107 --- /dev/null +++ b/blog/src/assets/media/claude-haiku-5-5/motion.css @@ -0,0 +1,13 @@ +/* Bright coded scenes for "Claude Haiku 5.5". Pairs with motion.js. */ +.prose figure.mg { margin: 42px 0; } +.prose figure.mg img, .mg .mg-svg { display: block; width: 100%; height: auto; border: 1px solid #1A1320; border-radius: 18px; background: #fff; } +.mg figcaption { font: 500 13px/1.5 "Space Grotesk", system-ui, sans-serif; color: #6B5878; padding-top: 10px; text-align: center; } +.mg .mg-svg { touch-action: manipulation; -webkit-tap-highlight-color: transparent; } +.mg .mg-svg text { -webkit-user-select: none; user-select: none; pointer-events: none; } +.mg .mg-hit { cursor: pointer; outline: none; } +.mg [role="slider"] { cursor: grab; touch-action: none; } +.mg .mg-ring { stroke-opacity: 0; transition: stroke-opacity 0.15s; } +.mg .mg-hit:focus-visible .mg-ring { stroke-opacity: 1; } +.mg [role="slider"]:focus-visible circle:nth-child(2) { stroke-width: 5; } +@media (hover: hover) { .mg .mg-hit:hover .mg-ring { stroke-opacity: 0.5; } } +@media (prefers-reduced-motion: reduce) { .mg .mg-ring { transition: none; } } diff --git a/blog/src/assets/media/claude-haiku-5-5/motion.js b/blog/src/assets/media/claude-haiku-5-5/motion.js new file mode 100644 index 000000000..bcbf7276c --- /dev/null +++ b/blog/src/assets/media/claude-haiku-5-5/motion.js @@ -0,0 +1,317 @@ +/* Bright coded scenes for "Claude Haiku 5.5". Vanilla JS, no library. +
holds a still image; this script swaps in a live SVG. + Plays only in view, honours reduced motion, "?mgstill" freezes each scene on its still frame. */ +(() => { + const NS = "http://www.w3.org/2000/svg"; + const INK = "#1A1320", YEL = "#FFCA54", BLUE = "#6C8EF5", LIL = "#B69CFF", MINT = "#7FD8AE", SKY = "#9AD8FF", SOFT = "#F1ECF9", MUTE = "#7A6A88"; + const SANS = '"Space Grotesk", system-ui, sans-serif', MONO = '"JetBrains Mono", ui-monospace, monospace'; + const el = (t, a = {}, p) => { const n = document.createElementNS(NS, t); for (const k in a) n.setAttribute(k, a[k]); if (p) p.appendChild(n); return n; }; + const txt = (p, x, y, s, a = {}) => { const n = el("text", Object.assign({ x, y, "font-family": SANS, "font-size": 24, "font-weight": 600, fill: INK }, a), p); n.textContent = s; return n; }; + const cl = (v, a = 0, b = 1) => Math.max(a, Math.min(b, v)); + const seg = (t, a, b) => cl((t - a) / (b - a)); + const oc = (x) => 1 - Math.pow(1 - x, 3); + const ob = (x) => { const c = 1.70158; return 1 + (c + 1) * Math.pow(x - 1, 3) + c * Math.pow(x - 1, 2); }; + const io = (x) => (x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2); + const tf = (n, x, y, s = 1, r = 0) => n.setAttribute("transform", `translate(${x} ${y}) rotate(${r}) scale(${s})`); + const button = (g, label, fn) => { + g.setAttribute("role", "button"); g.setAttribute("tabindex", "0"); g.setAttribute("aria-label", label); g.classList.add("mg-hit"); + g.addEventListener("click", fn); + g.addEventListener("keydown", (e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); fn(); } }); + }; + const strip = (svg, y, w = 680) => { + el("rect", { x: (800 - w) / 2, y, width: w, height: 48, rx: 24, fill: SOFT }, svg); + return txt(svg, 400, y + 31, "", { "text-anchor": "middle", "font-size": 20, "font-weight": 500 }); + }; + + const GREY = "#B69CFF"; + const pillFit = (g, t, pad) => { const r = g.querySelector("rect"), w = t.getComputedTextLength() + pad; r.setAttribute("x", -w / 2); r.setAttribute("width", w); return w; }; + + const SC = {}; + + /* ---- 1. one stopwatch runs and stops; two paper labels carry the claim and its footnote ---- */ + SC.stopwatch = { + dur: 11, still: 8.6, + build(svg, api) { + txt(svg, 44, 62, "Anthropic's speed claim", { "font-size": 32, "font-weight": 700 }); + txt(svg, 44, 98, "Announcement of 7 October 2026", { "font-size": 20, "font-weight": 500, fill: MUTE }); + txt(svg, 756, 60, "tap the stopwatch", { "text-anchor": "end", "font-size": 20, fill: MUTE, "font-weight": 500 }); + const CX = 236, CY = 318, R = 138; + const w = el("g", {}, svg); + const crown = el("g", {}, w); + el("rect", { x: -20, y: -R - 44, width: 40, height: 30, rx: 8, fill: SOFT, stroke: INK, "stroke-width": 3 }, crown); + el("rect", { x: -11, y: -R - 18, width: 22, height: 20, fill: "#fff", stroke: INK, "stroke-width": 3 }, w); + el("rect", { x: -13, y: -R - 30, width: 26, height: 22, rx: 6, fill: LIL, stroke: INK, "stroke-width": 3, transform: "rotate(42)" }, w); + el("circle", { r: R, fill: YEL, stroke: INK, "stroke-width": 3 }, w); + el("circle", { r: R - 22, fill: "#fff", stroke: INK, "stroke-width": 3 }, w); + for (let i = 0; i < 60; i++) { const big = i % 5 === 0; el("path", { d: `M0 ${-(R - 30)} V${-(R - (big ? 42 : 37))}`, stroke: big ? INK : GREY, "stroke-width": big ? 3 : 2, "stroke-linecap": "round", transform: `rotate(${i * 6})` }, w); } + const arc = el("circle", { r: R - 54, fill: "none", stroke: SKY, "stroke-width": 10, "stroke-linecap": "round", pathLength: 360, transform: "rotate(-90)" }, w); + txt(w, 0, 50, "Haiku 5.5", { "text-anchor": "middle", "font-size": 24, "font-weight": 700 }); + const hand = el("g", {}, w); + el("path", { d: `M0 22 V${-(R - 44)}`, stroke: INK, "stroke-width": 5, "stroke-linecap": "round" }, hand); + el("circle", { r: 10, fill: BLUE, stroke: INK, "stroke-width": 3 }, w); + el("circle", { r: R + 10, fill: "#fff", "fill-opacity": 0, stroke: INK, "stroke-width": 2, "stroke-dasharray": "3 7", class: "mg-ring" }, w); + button(w, "Stopwatch for Haiku 5.5. Press to run it again.", () => api.seek(0.2)); + const label = (y, fill, a, b, rot) => { + const g = el("g", {}, svg); + el("rect", { x: 0, y: -52, width: 300, height: 104, rx: 16, fill, stroke: INK, "stroke-width": 3 }, g); + el("circle", { cx: 26, cy: 0, r: 8, fill: "#fff", stroke: INK, "stroke-width": 3 }, g); + txt(g, 52, -8, a, { "font-size": 24, "font-weight": 700 }); + txt(g, 52, 24, b, { "font-size": 24, "font-weight": 500 }); + return { g, y, rot }; + }; + const A = label(252, YEL, "fastest to date", "at standard speed", -2.5), B = label(384, LIL, "Opus in Fast Mode", "is quicker", 2); + const cap = strip(svg, 506, 640); + return (t) => { + const run = oc(seg(t, 0.8, 3.6)), deg = 312 * run, out = 1 - seg(t, 10.4, 10.9); + hand.setAttribute("transform", `rotate(${deg * out})`); + arc.setAttribute("stroke-dasharray", `${Math.max(0.01, deg * out)} 400`); arc.setAttribute("opacity", deg * out < 2 ? 0 : 1); + const press = Math.sin(seg(t, 0.55, 0.85) * Math.PI) + Math.sin(seg(t, 3.55, 3.85) * Math.PI); + crown.setAttribute("transform", `translate(0 ${8 * press})`); + const jolt = Math.sin(seg(t, 3.6, 4.0) * Math.PI) * 0.03; + tf(w, CX, CY, 1 + jolt); + [[A, 4.2], [B, 5.4]].forEach(([l, s]) => { const k = ob(seg(t, s, s + 0.6)) * out; tf(l.g, 820 - 384 * k, l.y, 1, l.rot * k); l.g.setAttribute("opacity", k <= 0 ? 0 : 1); }); + cap.textContent = t < 5.4 || t > 10.4 ? "Anthropic calls Haiku 5.5 its fastest at standard speed" : "Anthropic's claim. We have not tried it."; + }; + }, + }; + + /* ---- 2. a small measuring cup fills, spills over its lip and carries on into a larger one ---- */ + SC.cups = { + dur: 12.5, still: 9.6, + build(svg) { + txt(svg, 44, 62, "One model, two price tiers", { "font-size": 32, "font-weight": 700 }); + txt(svg, 44, 98, "Anthropic's prices for Haiku 5.5, per 1 million tokens", { "font-size": 20, "font-weight": 500, fill: MUTE }); + const G = 404; + const s1 = el("path", { stroke: SKY, "stroke-width": 12, fill: "none", "stroke-linecap": "round" }, svg); + const s2 = el("path", { stroke: SKY, "stroke-width": 12, fill: "none", "stroke-linecap": "round" }, svg); + /* tap */ + el("path", { d: "M50 150 H186 Q210 150 210 172 V184", stroke: INK, "stroke-width": 28, fill: "none", "stroke-linejoin": "round" }, svg); + el("path", { d: "M50 150 H186 Q210 150 210 172 V184", stroke: SOFT, "stroke-width": 22, fill: "none", "stroke-linejoin": "round" }, svg); + el("rect", { x: 44, y: 126, width: 14, height: 48, rx: 5, fill: LIL, stroke: INK, "stroke-width": 3 }, svg); + el("path", { d: "M128 136 V124", stroke: INK, "stroke-width": 3 }, svg); + const wh = el("rect", { x: 104, y: 112, width: 48, height: 13, rx: 6.5, fill: YEL, stroke: INK, "stroke-width": 3 }, svg); + const cup = (x, top, b, w, lip) => { + const r = 16, hw = lip ? 30 : 46, hh = lip ? 24 : 36; + const liq = el("path", { fill: SKY }, svg); + const n = lip ? 3 : 5; + for (let i = 1; i <= n; i++) el("path", { d: `M${x + 3} ${b - (i * (b - top)) / (n + 1)} h${i % 2 ? 18 : 28}`, stroke: INK, "stroke-width": 2.5, "stroke-linecap": "round" }, svg); + el("path", { d: `M${x + w} ${top + 26} q${hw} 0 ${hw} ${hh} q0 ${hh} -${hw} ${hh}`, stroke: INK, "stroke-width": 3, fill: "none", "stroke-linecap": "round", transform: lip ? `translate(${2 * x + w} 0) scale(-1 1)` : "" }, svg); + el("path", { d: `M${x} ${top} V${b - r} Q${x} ${b} ${x + r} ${b} H${x + w - r} Q${x + w} ${b} ${x + w} ${b - r} V${top}` + (lip ? ` l14 -8` : ""), stroke: INK, "stroke-width": 3, fill: "none", "stroke-linecap": "round", "stroke-linejoin": "round" }, svg); + return (lv) => { const y = b - (b - top) * lv; liq.setAttribute("d", lv <= 0.01 ? "" : `M${x + 1.5} ${y} H${x + w - 1.5} V${b - r} Q${x + w - 1.5} ${b - 1.5} ${x + w - r} ${b - 1.5} H${x + r} Q${x + 1.5} ${b - 1.5} ${x + 1.5} ${b - r} Z`); return y; }; + }; + el("rect", { x: 122, y: 292, width: 176, height: G - 292, rx: 12, fill: SOFT, stroke: INK, "stroke-width": 3 }, svg); + const small = cup(146, 200, 292, 128, true), big = cup(420, 262, G, 270, false); + el("path", { d: `M44 ${G} H756`, stroke: INK, "stroke-width": 3, "stroke-linecap": "round" }, svg); + const card = (cx, fill, head, a, b) => { + const g = el("g", {}, svg); + el("rect", { x: -150, y: 0, width: 300, height: 128, rx: 16, fill: "#fff", stroke: INK, "stroke-width": 3 }, g); + el("path", { d: "M-150 42 H150 V16 Q150 0 134 0 H-134 Q-150 0 -150 16 Z", fill, stroke: INK, "stroke-width": 3, "stroke-linejoin": "round" }, g); + txt(g, 0, 29, head, { "text-anchor": "middle", "font-size": 20, "font-weight": 700 }); + [["input", a, 76], ["output", b, 110]].forEach(([k, v, y]) => { txt(g, -126, y, k, { "font-size": 22, "font-weight": 500 }); txt(g, 126, y, v, { "text-anchor": "end", "font-family": MONO, "font-size": 26, "font-weight": 700 }); }); + return { g, cx }; + }; + const c1 = card(210, YEL, "prompts up to 100k tokens", "$0.10", "$0.50"), c2 = card(570, LIL, "prompts over 100k tokens", "$0.50", "$2.50"); + return (t) => { + const out = 1 - seg(t, 11.6, 12.3); + const on = seg(t, 0.5, 0.8) * (1 - seg(t, 8.2, 8.5)); + const f1 = seg(t, 0.8, 3.4), f2 = seg(t, 4.0, 8.4); + const y1 = small(0.93 * f1 * out), y2 = big(0.72 * f2 * out); + wh.setAttribute("transform", `rotate(${-9 * (seg(t, 0.3, 0.6) - seg(t, 8.0, 8.3))} 128 118)`); + const wob = Math.sin(t * 20) * 1.2; + s1.setAttribute("d", `M210 188 V${y1 + 4}`); s1.setAttribute("opacity", on); s1.setAttribute("stroke-width", 12 + wob); + const over = seg(t, 3.5, 3.9) * (1 - seg(t, 8.5, 8.8)); + s2.setAttribute("d", `M284 198 Q${284 + 204 * over} 184 ${284 + 216 * over} ${198 + (y2 - 194) * over}`); s2.setAttribute("opacity", over <= 0 ? 0 : 1); s2.setAttribute("stroke-width", 12 - wob); + [[c1, 3.4], [c2, 5.2]].forEach(([c, s]) => { const k = ob(seg(t, s, s + 0.5)) * out; tf(c.g, c.cx, 432 + 20 * (1 - k), 0.7 + 0.3 * k); c.g.setAttribute("opacity", cl(k * 3)); }); + }; + }, + }; + + /* ---- 3. four paper planes, one benchmark at a time; each lands as far as its score ---- */ + SC.planes = { + dur: 14, still: 4.8, + build(svg, api) { + const M = [["Haiku 5.5", YEL], ["Haiku 4.5", SKY], ["GPT-6 Luna", LIL], ["Sonnet 5.5", BLUE]]; + const B = [ + ["GDPval-AA v2.1", ["1620", "735", "1437", "1840"], 2000, ""], + ["OSWorld 2.1, offline subset", ["72.4%", "15.7%", "48.9%", "83.9%"], 100, ""], + ["Humanity's Last Exam, no tools", ["45.9%", "10.2%", null, "56.9%"], 100, ""], + ["Terminal-Bench 4.0", ["39.2%", "0.0%", "16.4%", "70.6%"], 100, ""], + ["FrontierCode 1.1 (Main)", ["46.4%", null, "42.4%", "52.1%"], 100, "Xhigh effort"], + ]; + const N = B.length, P = 2.8, X0 = 236, LEN = 400, Y = [164, 232, 300, 368]; + const at = (b, i) => { const v = B[b][1][i]; return v == null ? { x: X0, nr: 1 } : { x: X0 + (parseFloat(v) / B[b][2]) * LEN, nr: 0 }; }; + txt(svg, 44, 62, "Anthropic's own figures", { "font-size": 32, "font-weight": 700 }); + txt(svg, 44, 98, "Five rows we selected. We did not run them. NR means not reported.", { "font-size": 20, "font-weight": 500, fill: MUTE }); + el("path", { d: `M${X0 - 40} 132 V412`, stroke: INK, "stroke-width": 3, "stroke-linecap": "round" }, svg); + el("rect", { x: X0 - 40, y: 412, width: LEN + 64, height: 26, rx: 8, fill: SOFT, stroke: INK, "stroke-width": 3 }, svg); + for (let i = 1; i < 20; i++) el("path", { d: `M${X0 + (i * LEN) / 20} 412 v${i % 2 ? 9 : 15}`, stroke: INK, "stroke-width": 2.5 }, svg); + const pl = M.map(([name, col], i) => { + txt(svg, 44, Y[i] + 8, name, { "font-size": 22, "font-weight": 700 }); + const trail = el("path", { stroke: GREY, "stroke-width": 3, fill: "none", "stroke-linecap": "round", "stroke-dasharray": "2 9" }, svg); + const g = el("g", {}, svg); + const body = el("path", { d: "M-34 -15 L30 0 L-34 15 L-22 0 Z", fill: col, stroke: INK, "stroke-width": 3, "stroke-linejoin": "round" }, g); + el("path", { d: "M-22 0 H30", stroke: INK, "stroke-width": 2.5, "stroke-linecap": "round" }, g); + const v = txt(svg, 0, Y[i] + 9, "", { "font-size": 24, "font-weight": 700 }); + const note = txt(svg, 0, Y[i] + 8, "", { "font-size": 20, "font-weight": 500, fill: MUTE }); + return { trail, g, body, v, note, col }; + }); + el("rect", { x: 172, y: 478, width: 456, height: 52, rx: 26, fill: SOFT }, svg); + const name = txt(svg, 400, 512, "", { "text-anchor": "middle", "font-size": 22, "font-weight": 700 }); + let user = null, shown = 0; + const step = (d) => { user = { from: shown, to: (shown + d + N) % N, t0: api.now() }; api.poke(); }; + [[-1, 130, "Previous benchmark", "M5 -9 L-5 0 L5 9"], [1, 670, "Next benchmark", "M-5 -9 L5 0 L-5 9"]].forEach(([d, x, label, arrow]) => { + const g = el("g", { transform: `translate(${x} 504)` }, svg); + el("circle", { r: 32, fill: "none", stroke: INK, "stroke-width": 2, "stroke-dasharray": "3 7", class: "mg-ring" }, g); + el("circle", { r: 26, fill: "#fff", stroke: INK, "stroke-width": 3 }, g); + el("path", { d: arrow, stroke: INK, "stroke-width": 3.5, fill: "none", "stroke-linecap": "round", "stroke-linejoin": "round" }, g); + button(g, label, () => step(d)); + g.addEventListener("keydown", (e) => { const s = e.key === "ArrowRight" || e.key === "ArrowUp" ? 1 : e.key === "ArrowLeft" || e.key === "ArrowDown" ? -1 : 0; if (s) { e.preventDefault(); step(s); } }); + }); + return (t, now) => { + let idx, prev, u; + if (user) { idx = user.to; prev = user.from; u = cl((now - user.t0) / P); } + else { idx = Math.floor(t / P) % N; prev = (idx + N - 1) % N; u = (t % P) / P; } + shown = idx; name.textContent = B[idx][0]; + pl.forEach((p, i) => { + const a = at(prev, i), c = at(idx, i), k = io(seg(u, 0.02 + i * 0.03, 0.36 + i * 0.03)), x = a.x + (c.x - a.x) * k, lift = Math.sin(k * Math.PI); + tf(p.g, x, Y[i] - 16 * lift, 1, -9 * lift * Math.sign(c.x - a.x || 1) * Math.cos(k * Math.PI)); + p.trail.setAttribute("d", x - X0 < 34 ? "" : `M${X0 - 24} ${Y[i]} H${x - 46}`); + const s = B[idx][1][i], show = seg(u, 0.4 + i * 0.03, 0.5 + i * 0.03); + p.v.textContent = s == null ? "NR" : s; p.v.setAttribute("x", c.x + 44); p.v.setAttribute("opacity", show); + const nt = i === 3 ? B[idx][3] : ""; p.note.textContent = nt; if (nt) { p.note.setAttribute("x", c.x + 44 + p.v.getComputedTextLength() + 12); p.note.setAttribute("opacity", show); } + p.body.setAttribute("fill", c.nr && k > 0.5 ? "#fff" : p.col); p.body.setAttribute("stroke-dasharray", c.nr && k > 0.5 ? "6 6" : "none"); + }); + }; + }, + }; + + /* ---- 4. a postcard rack turns; the card at the front flips to show what the alias gives there ---- */ + SC.postcards = { + dur: 14.6, still: 12.6, + build(svg, api) { + const C = [[["Claude Platform", "on AWS"], "Haiku 4.5", SKY, "Claude Platform on AWS"], [["Amazon", "Bedrock"], "Haiku 4.5", LIL, "Amazon Bedrock"], [["Google Cloud's", "Agent Platform"], "Haiku 4.5", YEL, "Google Cloud's Agent Platform"], [["Microsoft", "Foundry"], "Haiku 4.5", BLUE, "Microsoft Foundry"], [["Anthropic", "API"], "Haiku 5.5", MINT, "the Anthropic API"]]; + const N = C.length, P = 2.6, R = 262, CY = 296, W = 230, H = 276; + txt(svg, 44, 62, "Where the haiku alias points", { "font-size": 32, "font-weight": 700 }); + txt(svg, 44, 98, "Claude Code model docs, read 8 Oct 2026", { "font-size": 20, "font-weight": 500, fill: MUTE }); + txt(svg, 756, 60, "tap to turn", { "text-anchor": "end", "font-size": 20, fill: MUTE, "font-weight": 500 }); + el("ellipse", { cx: 400, cy: CY, rx: R, ry: 22, fill: "none", stroke: GREY, "stroke-width": 3, "stroke-dasharray": "2 9", "stroke-linecap": "round" }, svg); + const layer = el("g", {}, svg); + el("rect", { x: 34, y: 116, width: 732, height: 374, rx: 26, fill: "#fff", "fill-opacity": 0, stroke: INK, "stroke-width": 2, "stroke-dasharray": "3 7", class: "mg-ring" }, layer); + const pole = el("g", {}, layer); + el("rect", { x: 330, y: 462, width: 140, height: 20, rx: 10, fill: SOFT, stroke: INK, "stroke-width": 3 }, pole); + el("path", { d: "M400 128 V462", stroke: INK, "stroke-width": 6, "stroke-linecap": "round" }, pole); + el("circle", { cx: 400, cy: 124, r: 11, fill: YEL, stroke: INK, "stroke-width": 3 }, pole); + const cards = C.map(([nm, model, col]) => { + const g = el("g", {}, layer), flip = el("g", {}, g); + const front = el("g", {}, flip), back = el("g", {}, flip); + el("rect", { x: -W / 2, y: -H / 2, width: W, height: H, rx: 18, fill: "#fff", stroke: INK, "stroke-width": 3 }, front); + const ft = el("g", {}, front); + el("rect", { x: W / 2 - 62, y: -H / 2 + 18, width: 44, height: 52, rx: 6, fill: col, stroke: INK, "stroke-width": 3 }, ft); + nm.forEach((s, i) => txt(ft, 0, -8 + i * 34, s, { "text-anchor": "middle", "font-size": 26, "font-weight": 700 })); + el("path", { d: `M${-W / 2 + 28} 74 H${W / 2 - 28} M${-W / 2 + 28} 98 H${W / 2 - 70}`, stroke: SOFT, "stroke-width": 6, "stroke-linecap": "round" }, ft); + el("rect", { x: -W / 2, y: -H / 2, width: W, height: H, rx: 18, fill: model === "Haiku 5.5" ? MINT : SOFT, stroke: INK, "stroke-width": 3 }, back); + const bt = el("g", {}, back); + const pg = el("g", { transform: "translate(0 -92)" }, bt); + el("rect", { x: -52, y: -22, width: 104, height: 44, rx: 12, fill: "#fff", stroke: INK, "stroke-width": 3 }, pg); + txt(pg, 0, 8, "haiku", { "text-anchor": "middle", "font-family": MONO, "font-size": 24, "font-weight": 700 }); + txt(bt, 0, -34, "resolves to", { "text-anchor": "middle", "font-size": 24, "font-weight": 500 }); + txt(bt, 0, 14, model, { "text-anchor": "middle", "font-size": 40, "font-weight": 700 }); + el("path", { d: `M${-W / 2 + 28} 40 H${W / 2 - 28}`, stroke: INK, "stroke-width": 2.5, "stroke-linecap": "round", "stroke-dasharray": "2 8" }, bt); + nm.forEach((s, i) => txt(bt, 0, 78 + i * 30, s, { "text-anchor": "middle", "font-size": 24, "font-weight": 600 })); + return { g, flip, front, back, ft, bt }; + }); + const cap = strip(svg, 506, 700); + let last = 0, key = ""; + button(layer, "Postcard rack. Press to turn to the next provider.", () => { const k = Math.min(N - 1, Math.floor(last / P)); api.seek(((k + 1) % N) * P + 0.02); }); + return (t) => { + last = t; + const k = Math.min(N - 1, Math.floor(t / P)), u = t - k * P, pos = k - 1 + io(seg(u, 0, 0.9)), back = seg(t, N * P + 0.9, N * P + 1.4); + const order = [[0, pole]]; + cards.forEach((c, i) => { + const a = ((i - pos) * 2 * Math.PI) / N, z = Math.cos(a), s = 0.64 + 0.36 * (z + 1) / 2; + tf(c.g, 400 + R * Math.sin(a), CY + 16 * z, s); + const f = (i < k ? 1 : i === k ? io(seg(u, 1.05, 1.6)) : 0) * (1 - io(back)), sx = Math.abs(Math.cos(f * Math.PI)); + c.flip.setAttribute("transform", `scale(${Math.max(0.02, sx)} 1)`); + c.front.setAttribute("display", f > 0.5 ? "none" : ""); c.back.setAttribute("display", f > 0.5 ? "" : "none"); + const vis = seg(z, -0.05, 0.28); c.ft.setAttribute("opacity", vis); c.bt.setAttribute("opacity", vis); + order.push([z, c.g]); + }); + order.sort((p, q) => p[0] - q[0]); + const nk = order.map((o) => (o[1] === pole ? "p" : cards.findIndex((c) => c.g === o[1]))).join(""); + if (nk !== key) { key = nk; order.forEach((o) => layer.appendChild(o[1])); } + cap.textContent = u < 1.35 || back > 0 ? "In Claude Code, the haiku alias depends on your provider" : `On ${C[k][3]}, haiku resolves to ${C[k][1]}`; + }; + }, + }; + + /* ---- title card, 16 by 9: a row of dominoes part way through falling ---- */ + SC.hero = { + w: 960, h: 540, dur: 9, still: 2.7, + build(svg) { + const kg = el("g", { transform: "translate(64 62)" }, svg); + const kr = el("rect", { x: 0, y: 0, height: 40, rx: 20, fill: SOFT, stroke: INK, "stroke-width": 2.5 }, kg); + const kt = txt(kg, 20, 28, "Concepts", { "font-size": 22, "font-weight": 700 }); + kr.setAttribute("width", kt.getComputedTextLength() + 40); + const title = txt(svg, 62, 206, "Claude Haiku 5.5", { "font-size": 96, "font-weight": 700 }); + el("path", { d: `M66 236 H${62 + title.getComputedTextLength() - 6}`, stroke: YEL, "stroke-width": 14, "stroke-linecap": "round" }, svg); + txt(svg, 64, 292, "Checked 8 Oct 2026", { "font-size": 26, "font-weight": 500, fill: MUTE }); + const G = 478, DW = 20, DH = 96, D = 52, n = 15, TH = (Math.acos(DW / D) * 180) / Math.PI; + el("path", { d: `M64 ${G} H896`, stroke: INK, "stroke-width": 3, "stroke-linecap": "round" }, svg); + const COL = [YEL, SKY, LIL, MINT, BLUE]; + const ds = Array.from({ length: n }, (_, i) => { + const g = el("g", {}, svg); + el("rect", { x: -DW, y: -DH, width: DW, height: DH, rx: 5, fill: COL[i % 5], stroke: INK, "stroke-width": 3 }, g); + return g; + }); + const RAD = Math.PI / 180; + const fits = (a, b) => { + const px = DH * Math.sin(a), py = DH * Math.cos(a), bx = D - DW * Math.cos(b), by = DW * Math.sin(b); + const along = (px - bx) * Math.sin(b) + (py - by) * Math.cos(b), side = (px - bx) * Math.cos(b) - (py - by) * Math.sin(b); + if (along <= DH) return side <= 0.3; + return (bx + DH * Math.sin(b)) * Math.cos(a) - (by + DH * Math.cos(b)) * Math.sin(a) >= -0.3; + }; + return (t) => { + const up = 1 - io(seg(t, 7.6, 8.6)); + let next = null; + for (let i = n - 1; i >= 0; i--) { + const k = seg(t, 0.6 + i * 0.24, 1.3 + i * 0.24); + let a = 90 * k * k * RAD; + if (next != null && !fits(a, next)) { let lo = 0, hi = a; for (let j = 0; j < 22; j++) { const m = (lo + hi) / 2; if (fits(m, next)) lo = m; else hi = m; } a = lo; } + next = a; + ds[i].setAttribute("transform", `translate(${104 + i * D} ${G}) rotate(${(a / RAD) * up})`); + } + }; + }, + }; + + /* ---- player ---- */ + const q = new URLSearchParams(location.search), frozen = q.has("mgstill"), fixed = parseFloat(q.get("mgstill")); + const calm = matchMedia("(prefers-reduced-motion: reduce)").matches; + const mount = (fig) => { + const sc = SC[fig.dataset.scene], img = fig.querySelector("img"); if (!sc || !img) return; + const W = sc.w || 800, H = sc.h || 600; + const svg = el("svg", { viewBox: `0 0 ${W} ${H}`, class: "mg-svg", role: "group", "aria-label": img.alt || "" }); + svg.style.aspectRatio = `${W} / ${H}`; + el("rect", { width: W, height: H, fill: "#fff" }, svg); + img.replaceWith(svg); + let off = 0, raf = 0, seen = false, held = calm; + const base = performance.now(), clock = () => (performance.now() - base) / 1000; + let draw = () => {}; + const frame = () => { const now = clock(); draw(held ? sc.still : (((now + off) % sc.dur) + sc.dur) % sc.dur, now); }; + const tick = () => { cancelAnimationFrame(raf); frame(); if (seen && !held) raf = requestAnimationFrame(tick); }; + const api = { now: clock, seek: (s) => { off = s - clock(); held = false; tick(); }, poke: () => { held = false; tick(); } }; + draw = sc.build(svg, api); + if (frozen) { draw(isNaN(fixed) ? sc.still : fixed, 0); return; } + new IntersectionObserver(([e]) => { + seen = e.isIntersecting; + if (seen) { tick(); if (!fig.dataset.sent && window.posthog) { fig.dataset.sent = 1; window.posthog.capture("blog_scene_view", { slug: location.pathname.split("/").filter(Boolean).pop(), scene: fig.dataset.scene }); } } + else cancelAnimationFrame(raf); + }, { threshold: 0.25 }).observe(fig); + svg.addEventListener("click", () => { if (!fig.dataset.hit && window.posthog) { fig.dataset.hit = 1; window.posthog.capture("blog_scene_interact", { slug: location.pathname.split("/").filter(Boolean).pop(), scene: fig.dataset.scene }); } }); + frame(); + }; + const go = () => document.querySelectorAll("figure.mg[data-scene]").forEach(mount); + const fonts = document.fonts && document.fonts.load ? Promise.all([document.fonts.load('700 32px "Space Grotesk"'), document.fonts.load('500 20px "Space Grotesk"'), document.fonts.load('700 20px "JetBrains Mono"')]).catch(() => {}) : Promise.resolve(); + const start = () => fonts.then(go, go); + if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", start); else start(); +})(); diff --git a/blog/src/assets/media/claude-haiku-5-5/planes.png b/blog/src/assets/media/claude-haiku-5-5/planes.png new file mode 100644 index 000000000..b57c59d02 Binary files /dev/null and b/blog/src/assets/media/claude-haiku-5-5/planes.png differ diff --git a/blog/src/assets/media/claude-haiku-5-5/postcards.png b/blog/src/assets/media/claude-haiku-5-5/postcards.png new file mode 100644 index 000000000..24b9bcac6 Binary files /dev/null and b/blog/src/assets/media/claude-haiku-5-5/postcards.png differ diff --git a/blog/src/assets/media/claude-haiku-5-5/stopwatch.png b/blog/src/assets/media/claude-haiku-5-5/stopwatch.png new file mode 100644 index 000000000..933b39827 Binary files /dev/null and b/blog/src/assets/media/claude-haiku-5-5/stopwatch.png differ diff --git a/blog/src/posts/claude-code-subagents-vs-multi-agent-harness.md b/blog/src/posts/claude-code-subagents-vs-multi-agent-harness.md index f6051307c..019e31a5c 100644 --- a/blog/src/posts/claude-code-subagents-vs-multi-agent-harness.md +++ b/blog/src/posts/claude-code-subagents-vs-multi-agent-harness.md @@ -79,7 +79,7 @@ You can also force it: name the subagent in plain words, @-mention it with `@age ## How do you set a subagent's model and tools? -Use `model` and `tools` in the front matter. The model is resolved in this order: a model Claude passes when it spawns the subagent, then the `model` field, then the `CLAUDE_CODE_SUBAGENT_MODEL` variable, then your session's model. Since 2.1.251 that variable is only a default. To force one model on every subagent, also set `CLAUDE_CODE_SUBAGENT_MODEL_FORCE=1` (2.1.257 and later). Run `/tasks` to see which model each subagent is on. +Use `model` and `tools` in the front matter. The model is resolved in this order: a model Claude passes when it spawns the subagent, then the `model` field, then the `CLAUDE_CODE_SUBAGENT_MODEL` variable, then your session's model. Since 2.1.251 that variable is only a default. To force one model on every subagent, also set `CLAUDE_CODE_SUBAGENT_MODEL_FORCE=1` (2.1.257 and later). Run `/tasks` to see which model each subagent is on. The newest Haiku is [Claude Haiku 5.5](/blog/claude-haiku-5-5/). `tools` is an allowlist and `disallowedTools` a denylist. A `disallowedTools` entry such as `Bash(git push *)` removes the whole Bash tool, so block single commands with a deny rule in settings instead. The Task tool was renamed Agent in 2.1.63, and old `Task(...)` rules still work. diff --git a/blog/src/posts/claude-haiku-5-5.md b/blog/src/posts/claude-haiku-5-5.md new file mode 100644 index 000000000..560779a77 --- /dev/null +++ b/blog/src/posts/claude-haiku-5-5.md @@ -0,0 +1,112 @@ +--- +title: "Claude Haiku 5.5: price, benchmarks and where it fits" +description: "Claude Haiku 5.5 is Anthropic's new small model. Its tiered price, Anthropic's own scores and how to pick it in Claude Code, checked 8 Oct 2026." +date: 2026-10-08 +category: concepts +categoryLabel: Concepts +type: Non-technical +primaryKeyword: "claude haiku 5.5" +secondaryKeywords: ["claude haiku", "haiku 5.5", "claude haiku 5.5 pricing", "claude haiku 5.5 vs haiku 4.5", "claude haiku 5.5 claude code", "claude-haiku-5-5"] +tags: ["Concepts", "Claude Code", "AI Agents"] +faq: + - q: "How much does Claude Haiku 5.5 cost?" + a: "Anthropic's announcement of 7 October 2026 lists $0.10 input and $0.50 output per million tokens for prompts up to 100,000 tokens, and $0.50 input and $2.50 output for prompts over 100,000 tokens. Cache reads are $0.01 and $0.05. Checked 8 Oct 2026." + - q: "Is Claude Haiku 5.5 better than Haiku 4.5?" + a: "On Anthropic's own figures, yes on every row where both have a score. For example, the announcement lists 72.4% for Haiku 5.5 and 15.7% for Haiku 4.5 on the offline subset of OSWorld 2.1. We did not run these tests." + - q: "Is Claude Haiku 5.5 better than Sonnet 5.5?" + a: "No. Sonnet 5.5 is ahead on every row of Anthropic's own benchmark table, and the announcement says Sonnet 5.5 and Opus 5.5 remain better choices for complex agentic coding tasks. Haiku 5.5 is the cheaper and faster option." + - q: "What is the model ID for Claude Haiku 5.5?" + a: "It is claude-haiku-5-5 on the Claude API, Google Cloud, Microsoft Foundry and Claude Platform on AWS, and anthropic.claude-haiku-5-5 on Amazon Bedrock, according to Anthropic's model page read on 8 Oct 2026." + - q: "How do I use Claude Haiku 5.5 in Claude Code?" + a: "Claude Code's model docs say to run /model claude-haiku-5-5 in a session, or start with claude --model claude-haiku-5-5. The same page says to use Claude Code v2.1.293 or later with Haiku 5.5. Read on 8 Oct 2026." +--- + +Claude Haiku 5.5 is Anthropic's new small model: much cheaper than Haiku 4.5 on prompts up to 100,000 tokens, and behind Sonnet 5.5 on every row of Anthropic's own benchmark table. Anthropic released it on 7 October 2026. We have not tried it. Checked 8 Oct 2026. + +[Munder Difflin](https://harnessmd.com/download) is free and open source: a desktop app that runs a team of coding agents such as Claude Code, Codex and Gemini CLI on your own computer. A cheaper small model matters when several agents run at once, which is why we cover it. The [install guide](/blog/how-to-install-and-use-munder-difflin/) covers setup and the [Concepts hub](/blog/topics/concepts/) explains the terms. + +## What is Claude Haiku 5.5? + +It is Anthropic's new small model, with the model ID `claude-haiku-5-5`. Anthropic's [announcement](https://www.anthropic.com/claude-haiku-5-5), dated October 7, 2026, calls it "the cheapest, fastest, and most capable small model we've ever released" and says it is designed for high-volume, cost-sensitive tasks. + +The speed claim has a footnote. Anthropic says Haiku 5.5 is its fastest model to date at each model's standard speed, although it runs less quickly than its Opus models in Fast Mode. + +Anthropic's [model page](https://platform.claude.com/docs/en/models/haiku-5-5/overview), read on 8 Oct 2026, lists a 1M token context window and a maximum output of 128K tokens. The announcement adds that this is the first Haiku-class model with an adjustable effort setting. + +The [Hacker News thread](https://news.ycombinator.com/item?id=49996437) had more than 300 points and 140 comments when we checked on 8 Oct 2026. + +
Animation. A stopwatch labelled Haiku 5.5 starts, its hand sweeps round and stops. Two paper labels slide in beside it: one reads fastest to date at standard speed, the other reads Opus in Fast Mode is quicker.
Anthropic calls Haiku 5.5 its fastest model to date at standard speed, with Opus in Fast Mode quicker. Announcement of 7 October 2026.
+ +## What does Claude Haiku 5.5 cost? + +It costs $0.10 per million input tokens and $0.50 per million output tokens for prompts up to 100,000 tokens, as of 8 Oct 2026, and five times that above. These are the prices in the table in Anthropic's [announcement](https://www.anthropic.com/claude-haiku-5-5), per 1 million tokens. + +| Price per 1M tokens | Haiku 5.5, prompts up to 100k | Haiku 5.5, prompts over 100k | Haiku 4.5 | Sonnet 5.5 | +| --- | --- | --- | --- | --- | +| Input | $0.10 | $0.50 | $1.00 | $2.00 | +| Output | $0.50 | $2.50 | $5.00 | $10.00 | +| Cache writes | $0.125 | $0.625 | $1.25 | $2.50 | +| Cache reads | $0.01 | $0.05 | $0.10 | $0.10 | + +Anthropic says prompts up to 100,000 tokens made up around 90% of requests to its previous Haiku model. Its headline is that Haiku 5.5 costs around 75% less to run on average. A footnote explains the gap: the price is 90% lower for requests up to 100,000 tokens, less for larger ones, and an updated tokenizer uses slightly more tokens per task. The model page says the same text counts as approximately 30% more tokens than on Haiku 4.5. + +The model page also lists a 50% Batch API discount on input and output. For the wider bill, see [how much Claude Code costs](/blog/how-much-does-claude-code-cost/). + +
Animation. A tap fills a small measuring cup, and a card under it headed prompts up to 100k tokens shows $0.10 input and $0.50 output. The water spills over the lip into a larger cup, and its card headed prompts over 100k tokens shows $0.50 input and $2.50 output.
Anthropic's prices per 1 million tokens, in two tiers by prompt size. Checked 8 Oct 2026.
+ +## How does Claude Haiku 5.5 score on benchmarks? + +On Anthropic's own figures it is far ahead of Haiku 4.5 and behind Sonnet 5.5. The five rows below are our selection from the eight rows in the [announcement](https://www.anthropic.com/claude-haiku-5-5) table. We did not run them. NR means not reported. + +| Benchmark (as named by Anthropic) | Haiku 5.5 | Haiku 4.5 | GPT-6 Luna | Sonnet 5.5 | +| --- | --- | --- | --- | --- | +| GDPval-AA v2.1 | 1620 | 735 | 1437 | 1840 | +| OSWorld 2.1, offline subset | 72.4% | 15.7% | 48.9% | 83.9% | +| Humanity's Last Exam, no tools | 45.9% | 10.2% | NR | 56.9% | +| Terminal-Bench 4.0 | 39.2% | 0.0% | 16.4% | 70.6% | +| FrontierCode 1.1 (Main) | 46.4% | NR | 42.4% | 52.1% | + +Sonnet 5.5 leads on all eight rows of the full table. Anthropic marks its FrontierCode figure for Sonnet 5.5 as Xhigh effort. Haiku 5.5 is ahead of GPT-6 Luna on all six rows where Anthropic reports both. + +The coding gap is the one to notice. On Terminal-Bench 4.0, Haiku 5.5 is at 39.2% against 70.6% for Sonnet 5.5. Anthropic says so itself: "Sonnet 5.5 and Opus 5.5 remain better choices for complex agentic coding tasks like those measured by Terminal-Bench 4.0." + +
Animation. Four paper planes for Haiku 5.5, Haiku 4.5, GPT-6 Luna and Sonnet 5.5 glide along a ruled strip and land at distances set by their scores on one benchmark at a time. Arrow buttons step through the five benchmarks.
Anthropic's own figures, five rows we selected from its table of 7 October 2026. We did not run them.
+ +## Where can you use Claude Haiku 5.5? + +Anthropic says it "is available now on all platforms, including Amazon Web Services, Google Cloud, and Microsoft Azure". The [model page](https://platform.claude.com/docs/en/models/haiku-5-5/overview) lists the Claude API, Amazon Bedrock, Google Cloud, Microsoft Foundry and Claude Platform on AWS. The ID is `claude-haiku-5-5`, except on Amazon Bedrock, where it is `anthropic.claude-haiku-5-5`. + +Neither page says which Claude app plans include it, so we leave that out. + +## How do you use Claude Haiku 5.5 in Claude Code? + +Run `/model claude-haiku-5-5` in a session, or start with `claude --model claude-haiku-5-5`. That wording is from Claude Code's [model configuration docs](https://code.claude.com/docs/en/model-config), read on 8 Oct 2026. The same page says to use v2.1.293 or later with Haiku 5.5. + +Three details from the docs: + +* **The alias depends on your provider.** `haiku` resolves to Haiku 5.5 on the Anthropic API. On Claude Platform on AWS, Amazon Bedrock, Google Cloud's Agent Platform and Microsoft Foundry it resolves to Haiku 4.5. +* **Long prompts cost more.** The docs repeat that a Haiku 5.5 request costs more per token when its prompt is longer than 100K tokens. +* **Subagents take a model.** The [subagent docs](https://code.claude.com/docs/en/sub-agents) say the `model` field accepts an alias such as `haiku`, a full model ID or `inherit`. `CLAUDE_CODE_SUBAGENT_MODEL` sets a default. + +Our post on [Claude Code subagents](/blog/claude-code-subagents-vs-multi-agent-harness/) walks through that file. + +
Animation. A postcard rack turns slowly. Each card names a provider, and as it faces front it flips to show which model the haiku alias gives: Haiku 5.5 on the Anthropic API card, Haiku 4.5 on the other cards.
In Claude Code the haiku alias resolves to Haiku 5.5 on the Anthropic API and to Haiku 4.5 on the other listed providers. Docs read 8 Oct 2026.
+ +## What does it mean if you run a team of coding agents? + +We think it makes the split between a planner and its helpers cheaper to try. Anthropic says Haiku 5.5 "pairs well with Opus 5.5 and Sonnet 5.5 as a subagent on coding work", and that it suits narrowly scoped tasks like compaction, summarization or subagent work. + +Two customer quotes from the announcement, the first on subagents and the second on speed. Rogo: "The short and high-volume work is where Claude Haiku 5.5 fits for us, like quick lookups, subagents, and summaries." Asana: "Compared with the model we use today, we saw over a 30% reduction in latency for task completions and up to 2.5x faster inference per agent turn." + +Our view: put a bigger model on planning and hard debugging, and a small fast one on searching, summarising and running tests. The small one fetches, the big one decides. This is an idea, not a test. We have not tried Haiku 5.5. Our piece on [model routing](/blog/do-more-with-less-model-routing/) explains the reasoning. + +## What should you do now? + +Our view: try it on routine work first, and keep your bigger model where the task is hard. + +1. Update Claude Code to v2.1.293 or later. +2. Set `model: haiku` on one subagent that only searches or summarises. +3. Watch prompt size. The lower price applies up to 100,000 tokens. +4. Compare results on your own repo before trusting any table. + + diff --git a/docs/blog/agent-tools-today-2026-10-07/index.html b/docs/blog/agent-tools-today-2026-10-07/index.html index 0e2547c2c..0ed252b1d 100644 --- a/docs/blog/agent-tools-today-2026-10-07/index.html +++ b/docs/blog/agent-tools-today-2026-10-07/index.html @@ -241,7 +241,7 @@

How this list is built + + + + - + -