diff --git a/blog/src/_data/media.json b/blog/src/_data/media.json index 1f77259780..4a9bb3429a 100644 --- a/blog/src/_data/media.json +++ b/blog/src/_data/media.json @@ -3070,6 +3070,40 @@ }, "youtube": [] }, + "agent-tools-today-2026-10-30": { + "title": "Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App", + "category": "news", + "hero": { + "file": "assets/media/agent-tools-today/hero.png", + "alt": "Hand drawn sketch: a front page with five numbered lines, a clock, and a yellow character reading it out", + "prompt": "Series hero for the Agent Tools Today daily brief, drawn in code (media-src/topic-tiles.html?t=news). Reused by every brief.", + "status": "ready" + }, + "inline": {}, + "youtube": [] + }, + "what-is-instinct-ai": { + "title": "What Is Instinct AI? Access, Privacy and 6 Alternatives You Can Use Now (Oct 2026)", + "category": "concepts", + "hero": { + "file": "assets/media/what-is-instinct-ai/hero.png", + "alt": "Title card on white. What is Instinct AI? in large ink type, a Concepts pill, the line Private beta, plus 6 alternatives, Checked 30 Oct 2026, and three small chat bubbles", + "prompt": "Still of the hero scene in assets/media/what-is-instinct-ai/motion.js.", + "status": "ready" + }, + "inline": {} + }, + "meta-muse-alternatives": { + "title": "Meta Muse Alternatives: 7 Picks If Muse Isn't in Your Country or You Want Your Data Back (Oct 2026)", + "category": "comparisons", + "hero": { + "file": "assets/media/meta-muse-alternatives/hero.png", + "alt": "Title card on white. Meta Muse alternatives in large ink type, a Comparisons pill, the line 7 picks, open source and hosted, Checked 30 Oct 2026, and a small compass", + "prompt": "Still of the hero scene in assets/media/meta-muse-alternatives/motion.js.", + "status": "ready" + }, + "inline": {} + }, "the-hook-shim-pattern": { "title": "The Hook Shim Pattern: Wiring Agent Hooks to a Live Process", "category": "internals", diff --git a/blog/src/assets/media/agent-tools-today-2026-10-30/motion.css b/blog/src/assets/media/agent-tools-today-2026-10-30/motion.css new file mode 100644 index 0000000000..2c898d64a9 --- /dev/null +++ b/blog/src/assets/media/agent-tools-today-2026-10-30/motion.css @@ -0,0 +1,13 @@ +/* Bright coded scene for "Agent tools today, 30 Oct 2026". 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/agent-tools-today-2026-10-30/motion.js b/blog/src/assets/media/agent-tools-today-2026-10-30/motion.js new file mode 100644 index 0000000000..99ba30c86c --- /dev/null +++ b/blog/src/assets/media/agent-tools-today-2026-10-30/motion.js @@ -0,0 +1,115 @@ +/* Bright coded scene for "Agent tools today, 30 Oct 2026". 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 SC = {}; + + /* ---- three envelopes drop into a mail sorting rack ---- */ + SC.sorter = { + dur: 8.5, still: 7, + build(svg, api) { + const X0 = 48, DW = 16, S = (704 - 4 * DW) / 3, EW = 196, EH = 250, TOP = 270, OUT = 180; + const MAIL = [ + ["Mistral", "Large 4", "Weights out", SKY], + ["Claude Code", "2.1.314", "Write guard", LIL], + ["Herdr", "", "Desktop app", MINT], + ]; + const root = el("g", { transform: "translate(0 -64)" }, svg); + const grain = (d, p) => el("path", { d, stroke: "#fff", "stroke-opacity": 0.6, "stroke-width": 2.5, fill: "none", "stroke-linecap": "round" }, p); + el("ellipse", { cx: 400, cy: 560, rx: 370, ry: 10, fill: SOFT }, root); + el("rect", { x: X0 + 8, y: 216, width: 688, height: 316, rx: 10, fill: SOFT, stroke: INK, "stroke-width": 3 }, root); + for (let i = 0; i < 4; i++) { + const x = X0 + i * (S + DW); + el("rect", { x, y: 196, width: DW, height: 336, rx: 8, fill: YEL, stroke: INK, "stroke-width": 3 }, root); + grain(`M${x + 8} 214 V300 M${x + 8} 330 V440`, root); + } + const layer = el("g", {}, root); + el("rect", { x: 40, y: 454, width: 720, height: 78, rx: 12, fill: YEL, stroke: INK, "stroke-width": 3 }, root); + grain("M72 476 C200 468 330 486 460 476 S660 468 728 478", root); + grain("M120 506 C260 498 380 514 520 506 S640 500 690 506", root); + el("ellipse", { cx: 600, cy: 492, rx: 14, ry: 5, fill: "none", stroke: "#fff", "stroke-opacity": 0.6, "stroke-width": 2.5 }, root); + el("rect", { x: 28, y: 526, width: 744, height: 20, rx: 10, fill: YEL, stroke: INK, "stroke-width": 3 }, root); + const env = MAIL.map(([a, b, tag, col], i) => { + const g = el("g", {}, layer); + el("rect", { x: -8, y: -8, width: EW + 16, height: EH + 16, rx: 16, fill: "none", stroke: INK, "stroke-width": 2.5, "stroke-dasharray": "6 6", class: "mg-ring" }, g); + el("rect", { width: EW, height: EH, rx: 10, fill: "#fff", stroke: INK, "stroke-width": 3 }, g); + el("path", { d: `M4 5 L${EW / 2} 52 L${EW - 4} 5`, stroke: MUTE, "stroke-width": 2.5, fill: "none", "stroke-linejoin": "round", "stroke-linecap": "round" }, g); + const name = { "text-anchor": "middle", "font-family": MONO, "font-size": 24, "font-weight": 700 }; + if (b) { txt(g, EW / 2, 92, a, name); txt(g, EW / 2, 120, b, name); } else txt(g, EW / 2, 106, a, name); + const chip = el("rect", { y: 138, height: 34, rx: 17, fill: col, stroke: INK, "stroke-width": 2.5 }, g); + const tt = txt(g, EW / 2, 161, tag, { "text-anchor": "middle", "font-size": 19, "font-weight": 600 }); + const w = (tt.getComputedTextLength() || 110) + 32; + chip.setAttribute("x", EW / 2 - w / 2); chip.setAttribute("width", w); + const st = { out: false, at: -99 }; + button(g, `${b ? a + " " + b : a}, ${tag}`, () => { + st.out = !st.out; st.at = api.calm ? -99 : api.now(); g.setAttribute("aria-pressed", st.out); + if (api.calm) api.redraw(); else api.poke(); + }); + g.setAttribute("aria-pressed", "false"); + return { g, st, x: X0 + DW + i * (S + DW) + (S - EW) / 2, d: 0.5 + i * 1.4, r: [-7, 6, -5][i] }; + }); + return (t, now) => { + const fade = 1 - seg(t, 7.6, 8.2); + env.forEach((e) => { + const k = seg(t, e.d, e.d + 0.75), bump = Math.sin(seg(t, e.d + 0.75, e.d + 1.05) * Math.PI); + const p = io(seg(now - e.st.at, 0, 0.55)), slide = e.st.out ? -OUT * p : -OUT * (1 - p); + const y = TOP - 620 * (1 - k * k) - 14 * bump + slide, r = e.r * (1 - k) + e.r * 0.25 * bump; + e.g.setAttribute("transform", `translate(${e.x + EW / 2} ${y + EH / 2}) rotate(${r}) translate(${-EW / 2} ${-EH / 2})`); + e.g.setAttribute("opacity", t < e.d ? 0 : fade); + }); + }; + }, + }; + + /* ---- 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 = { calm, redraw: () => frame(), 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/agent-tools-today-2026-10-30/sorter.png b/blog/src/assets/media/agent-tools-today-2026-10-30/sorter.png new file mode 100644 index 0000000000..a53b116cfa Binary files /dev/null and b/blog/src/assets/media/agent-tools-today-2026-10-30/sorter.png differ diff --git a/blog/src/assets/media/meta-muse-alternatives/compass.png b/blog/src/assets/media/meta-muse-alternatives/compass.png new file mode 100644 index 0000000000..205fac8214 Binary files /dev/null and b/blog/src/assets/media/meta-muse-alternatives/compass.png differ diff --git a/blog/src/assets/media/meta-muse-alternatives/globe.png b/blog/src/assets/media/meta-muse-alternatives/globe.png new file mode 100644 index 0000000000..44423325a0 Binary files /dev/null and b/blog/src/assets/media/meta-muse-alternatives/globe.png differ diff --git a/blog/src/assets/media/meta-muse-alternatives/hero.png b/blog/src/assets/media/meta-muse-alternatives/hero.png new file mode 100644 index 0000000000..cee2c5e54e Binary files /dev/null and b/blog/src/assets/media/meta-muse-alternatives/hero.png differ diff --git a/blog/src/assets/media/meta-muse-alternatives/motion.css b/blog/src/assets/media/meta-muse-alternatives/motion.css new file mode 100644 index 0000000000..ae11628cf1 --- /dev/null +++ b/blog/src/assets/media/meta-muse-alternatives/motion.css @@ -0,0 +1,13 @@ +/* Bright coded scenes for "Meta Muse alternatives". 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/meta-muse-alternatives/motion.js b/blog/src/assets/media/meta-muse-alternatives/motion.js new file mode 100644 index 0000000000..35149bb66b --- /dev/null +++ b/blog/src/assets/media/meta-muse-alternatives/motion.js @@ -0,0 +1,245 @@ +/* Bright coded scenes for "Meta Muse alternatives". 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 }); + }; + + /* ---- a compass face drawn around 0,0; returns the needle group ---- */ + const compass = (g, r) => { + el("circle", { r: r + 14, fill: SKY, stroke: INK, "stroke-width": 3 }, g); + el("circle", { r, fill: "#fff", stroke: INK, "stroke-width": 3 }, g); + for (let i = 0; i < 24; i++) { + const a = (i * 15 * Math.PI) / 180, l = i % 6 === 0 ? 16 : 8; + el("path", { d: `M${Math.sin(a) * (r - 6)} ${-Math.cos(a) * (r - 6)} L${Math.sin(a) * (r - 6 - l)} ${-Math.cos(a) * (r - 6 - l)}`, stroke: INK, "stroke-width": i % 6 === 0 ? 3 : 2, "stroke-linecap": "round" }, g); + } + const n = el("g", {}, g), L = r - 26, w = r * 0.16; + el("path", { d: `M0 ${-L} L${w} 0 L${-w} 0 Z`, fill: BLUE, stroke: INK, "stroke-width": 3, "stroke-linejoin": "round" }, n); + el("path", { d: `M0 ${L * 0.72} L${w} 0 L${-w} 0 Z`, fill: "#fff", stroke: INK, "stroke-width": 3, "stroke-linejoin": "round" }, n); + el("circle", { r: w * 0.75, fill: YEL, stroke: INK, "stroke-width": 3 }, g); + return n; + }; + + const SC = {}; + + /* ---- 1. a globe turns, then three launch pins drop ---- */ + SC.globe = { + dur: 11, still: 10.5, + build(svg, api) { + const C = [400, 290], R = 185; + const clip = el("clipPath", { id: "mg-globe-clip" }, el("defs", {}, svg)); + el("circle", { cx: C[0], cy: C[1], r: R }, clip); + el("circle", { cx: C[0], cy: C[1], r: R, fill: SKY }, svg); + const sph = el("g", { "clip-path": "url(#mg-globe-clip)" }, svg); + const land = el("g", {}, sph); + const blobs = [ + "M262 158 Q300 128 352 144 Q384 156 378 196 Q372 232 342 248 Q330 276 304 284 Q282 270 286 238 Q262 214 252 190 Q248 170 262 158 Z", + "M330 302 Q362 296 380 318 Q392 352 372 392 Q356 428 340 434 Q330 404 332 370 Q318 336 330 302 Z", + "M440 286 Q480 272 506 292 Q520 326 500 360 Q482 398 464 402 Q450 372 452 340 Q430 312 440 286 Z", + "M450 150 Q500 128 556 146 Q584 166 572 196 Q546 214 512 210 Q480 224 458 206 Q438 178 450 150 Z", + "M548 236 Q560 232 566 244 Q568 262 556 276 Q546 284 542 272 Q540 252 548 236 Z", + ]; + [-400, 0, 400].forEach((dx) => { const g = el("g", { transform: `translate(${dx} 0)` }, land); blobs.forEach((d) => el("path", { d, fill: MINT, stroke: INK, "stroke-width": 2.5, "stroke-linejoin": "round" }, g)); }); + el("ellipse", { cx: C[0], cy: C[1], rx: R, ry: 26, fill: "none", stroke: "#fff", "stroke-width": 2.5, "stroke-opacity": 0.8 }, sph); + const mer = [0, 1].map(() => el("ellipse", { cx: C[0], cy: C[1], rx: R, ry: R, fill: "none", stroke: "#fff", "stroke-width": 2.5, "stroke-opacity": 0.8 }, sph)); + el("circle", { cx: C[0], cy: C[1], r: R, fill: "none", stroke: INK, "stroke-width": 3 }, svg); + const P = [ + { name: "US", date: "8 Sep", src: "Meta launch post", col: YEL, at: [318, 252], card: [40, 252, 150, 78], d: 3.0 }, + { name: "Canada", date: "18 Sep", src: "iPhone in Canada", col: BLUE, at: [332, 186], card: [40, 132, 150, 78], d: 4.2 }, + { name: "Japan", date: "23 Oct", src: "RuntimeWire", col: LIL, at: [554, 262], card: [612, 196, 156, 116], d: 5.4, note: "Reported" }, + ]; + const pins = P.map((p, i) => { + const g = el("g", {}, svg), [x, y] = p.at, [cx, cy, cw, ch] = p.card; + const shadow = el("ellipse", { cx: x, cy: y, rx: 12, ry: 4, fill: INK, "fill-opacity": 0.25 }, g); + const ex = cx + (cx < 400 ? cw : 0), ey = cy + 36; + const lead = el("path", { d: `M${x} ${y - 30} L${ex} ${ey}`, stroke: INK, "stroke-width": 2, "stroke-dasharray": "3 6", "stroke-linecap": "round", fill: "none" }, g); + const card = el("g", {}, g); + el("rect", { x: cx - 6, y: cy - 6, width: cw + 12, height: ch + 12, rx: 20, fill: "none", stroke: INK, "stroke-width": 2, "stroke-dasharray": "4 6", class: "mg-ring" }, card); + const face = el("rect", { x: cx, y: cy, width: cw, height: ch, rx: 16, fill: "#fff", stroke: INK, "stroke-width": 3 }, card); + txt(card, cx + 18, cy + 34, p.name, { "font-size": 26, "font-weight": 700 }); + txt(card, cx + 18, cy + 62, p.date, { "font-family": MONO, "font-size": 20, "font-weight": 500 }); + if (p.note) { el("rect", { x: cx + 14, y: cy + 76, width: 110, height: 28, rx: 14, fill: SOFT, stroke: INK, "stroke-width": 1.5 }, card); txt(card, cx + 69, cy + 96, p.note, { "text-anchor": "middle", "font-size": 16, "font-weight": 600, fill: MUTE }); } + const pin = el("g", {}, g); + el("path", { d: "M0 0 C-6 -10 -16 -20 -16 -32 A16 16 0 1 1 16 -32 C16 -20 6 -10 0 0 Z", fill: p.col, stroke: INK, "stroke-width": 3, "stroke-linejoin": "round" }, pin); + el("circle", { cx: 0, cy: -32, r: 6, fill: "#fff", stroke: INK, "stroke-width": 2.5 }, pin); + button(g, `${p.name}, ${p.date}${p.note ? ", " + p.note : ""}: ${p.src}`, () => { pinned = i; api.seek(6.4); }); + return { g, pin, shadow, lead, card, face, x, y }; + }); + let pinned = -1, last = 0; + const tip = strip(svg, 528, 560); + return (t) => { + if (t < last) pinned = -1; last = t; + const spin = io(seg(t, 0, 2.8)), shift = (700 * (1 - spin)) % 400; + land.setAttribute("transform", `translate(${shift} 0)`); + mer.forEach((m, i) => { const ph = (shift / 400) * Math.PI + Math.PI / 4 + i * Math.PI / 2; m.setAttribute("rx", Math.max(2, Math.abs(Math.cos(ph)) * R)); }); + let show = -1; + pins.forEach((p, i) => { + const k = seg(t, P[i].d, P[i].d + 0.55), drop = ob(k), c = oc(seg(t, P[i].d + 0.4, P[i].d + 0.9)); + tf(p.pin, p.x, p.y - 140 * (1 - drop)); p.pin.setAttribute("opacity", k > 0 ? 1 : 0); + p.shadow.setAttribute("opacity", k); p.lead.setAttribute("opacity", c); + p.card.setAttribute("opacity", c); p.card.setAttribute("transform", `translate(0 ${12 * (1 - c)})`); + p.face.setAttribute("fill", pinned === i ? P[i].col : "#fff"); + if (t >= P[i].d) show = i; + }); + if (pinned >= 0) show = pinned; + tip.textContent = show < 0 ? "Tapping a pin shows its source" : `${P[show].name}: ${P[show].src}`; + }; + }, + }; + + /* ---- 2. one training switch, On then Off ---- */ + SC.sliders = { + dur: 9, still: 8.6, + build(svg, api) { + const panel = el("g", {}, svg); + el("rect", { x: 60, y: 60, width: 680, height: 400, rx: 28, fill: "#fff", stroke: INK, "stroke-width": 3 }, panel); + txt(panel, 104, 140, "Muse", { "font-size": 46, "font-weight": 700 }); + const crumb = txt(panel, 104, 192, "", { "font-size": 24, "font-weight": 500, fill: MUTE }); + el("path", { d: "M104 230 H696", stroke: SOFT, "stroke-width": 4, "stroke-linecap": "round" }, panel); + el("rect", { x: 92, y: 262, width: 616, height: 160, rx: 22, fill: SOFT }, panel); + txt(panel, 128, 330, "Use my interactions", { "font-size": 30, "font-weight": 600 }); + txt(panel, 128, 370, "to improve models", { "font-size": 30, "font-weight": 600 }); + const sw = el("g", {}, panel); + el("rect", { x: 546, y: 288, width: 136, height: 88, rx: 44, fill: "none", stroke: INK, "stroke-width": 2, "stroke-dasharray": "4 6", class: "mg-ring" }, sw); + const track = el("rect", { x: 556, y: 298, width: 116, height: 68, rx: 34, stroke: INK, "stroke-width": 3 }, sw); + const pulse = el("circle", { r: 28, fill: "none", stroke: SKY, "stroke-width": 4 }, sw); + const knob = el("circle", { r: 25, cy: 332, fill: "#fff", stroke: INK, "stroke-width": 3 }, sw); + const word = txt(sw, 614, 405, "", { "text-anchor": "middle", "font-size": 22, "font-weight": 700 }); + sw.setAttribute("role", "switch"); + const LINE = "Settings, Data controls"; + let user = null, last = 0; + button(sw, "Use my interactions to improve models", () => { user = !(cur > 0.5); api.seek(5.4); }); + sw.setAttribute("role", "switch"); + el("rect", { x: 100, y: 500, width: 600, height: 48, rx: 24, fill: SOFT }, svg); + txt(svg, 400, 531, "Tapping the switch turns it back on or off", { "text-anchor": "middle", "font-size": 20, "font-weight": 500 }); + let cur = 1; + return (t) => { + if (t < last) user = null; last = t; + const p = ob(seg(t, 0, 0.7)); + panel.setAttribute("transform", `translate(400 260) scale(${0.85 + 0.15 * p}) translate(-400 -260)`); panel.setAttribute("opacity", seg(t, 0, 0.3)); + crumb.textContent = LINE.slice(0, Math.round(LINE.length * seg(t, 2.4, 3.6))); + const slide = io(seg(t, 4.3, 5.0)); + cur = user == null ? 1 - slide : user ? 1 : 0; + const kx = 590 + 48 * cur; + knob.setAttribute("cx", kx); + track.setAttribute("fill", cur > 0.5 ? BLUE : "#fff"); + word.textContent = cur > 0.5 ? "On" : "Off"; + sw.setAttribute("aria-checked", cur > 0.5 ? "true" : "false"); + const q = user == null ? seg(t, 5.0, 5.8) : 0; + pulse.setAttribute("cx", kx); pulse.setAttribute("cy", 332); + pulse.setAttribute("r", 26 + 30 * oc(q)); pulse.setAttribute("stroke-opacity", q > 0 && q < 1 ? 1 - q : 0); + }; + }, + }; + + /* ---- 3. a compass needle points at three reasons to leave ---- */ + SC.compass = { + dur: 10, still: 9.6, + build(svg, api) { + const C = [400, 268]; + el("rect", { x: 24, y: 22, width: 752, height: 380, rx: 28, fill: "#fff", stroke: INK, "stroke-width": 3 }, svg); + const D = [ + { label: "Not in my country", at: [152, 112], w: 232, col: YEL, pick: ["OpenClaw and", "Hermes Agent"] }, + { label: "Keep my data", at: [400, 72], w: 184, col: MINT, pick: ["Open source picks"] }, + { label: "Agents for work", at: [648, 112], w: 212, col: LIL, pick: ["Claude Cowork", "and Munder Difflin"] }, + ]; + D.forEach((d) => { d.ang = (Math.atan2(d.at[0] - C[0], C[1] - d.at[1]) * 180) / Math.PI; }); + const g = el("g", {}, svg); tf(g, C[0], C[1]); + const needle = compass(g, 104); + const chips = D.map((d, i) => { + const b = el("g", {}, svg), [x, y] = d.at; + el("rect", { x: x - d.w / 2 - 6, y: y - 30, width: d.w + 12, height: 60, rx: 30, fill: "none", stroke: INK, "stroke-width": 2, "stroke-dasharray": "4 6", class: "mg-ring" }, b); + const face = el("rect", { x: x - d.w / 2, y: y - 24, width: d.w, height: 48, rx: 24, fill: "#fff", stroke: INK, "stroke-width": 3 }, b); + txt(b, x, y + 8, d.label, { "text-anchor": "middle", "font-size": 22, "font-weight": 700 }); + button(b, `${d.label}: ${d.pick.join(" ")}`, () => { pick = i; from = angle; pickAt = api.now(); api.seek(6.6); }); + const card = el("g", {}, svg), cx = x; + el("rect", { x: cx - 115, y: 424, width: 230, height: 96, rx: 18, fill: "#fff", stroke: INK, "stroke-width": 3 }, card); + el("circle", { cx: cx - 96, cy: 444, r: 7, fill: d.col, stroke: INK, "stroke-width": 2 }, card); + d.pick.forEach((s, j) => txt(card, cx, (d.pick.length === 1 ? 480 : 466) + j * 30, s, { "text-anchor": "middle", "font-family": MONO, "font-size": 18, "font-weight": 700 })); + return { face, card }; + }); + el("rect", { x: 140, y: 540, width: 520, height: 44, rx: 22, fill: SOFT }, svg); + txt(svg, 400, 569, "Tapping a direction points the needle there", { "text-anchor": "middle", "font-size": 19, "font-weight": 500 }); + let pick = -1, from = 0, pickAt = 0, angle = 0, last = 0; + const swings = [[0, 1.6, -330, D[0].ang], [3.0, 3.9, D[0].ang, D[1].ang], [5.2, 6.1, D[1].ang, D[2].ang]]; + return (t, now) => { + if (t < last) pick = -1; last = t; + if (pick >= 0) angle = from + (D[pick].ang - from) * ob(seg(now - pickAt, 0, 0.7)); + else { angle = swings[0][2]; swings.forEach(([a, b, f, to]) => { if (t >= a) angle = f + (to - f) * ob(seg(t, a, b)); }); } + needle.setAttribute("transform", `rotate(${angle})`); + const at = pick >= 0 ? pick : t >= swings[2][0] + 0.5 ? 2 : t >= swings[1][0] + 0.5 ? 1 : t >= 1.2 ? 0 : -1; + chips.forEach((c, i) => { + c.face.setAttribute("fill", i === at ? D[i].col : "#fff"); + const k = oc(seg(t, [1.4, 3.8, 6.0][i], [1.9, 4.3, 6.5][i])); + c.card.setAttribute("opacity", pick >= 0 ? 1 : k); c.card.setAttribute("transform", `translate(0 ${pick >= 0 ? 0 : 16 * (1 - k)})`); + }); + }; + }, + }; + + /* ---- title card, 16 by 9 ---- */ + SC.hero = { + w: 960, h: 540, dur: 1, still: 0, + build(svg) { + el("rect", { x: 64, y: 62, width: 176, height: 44, rx: 22, fill: LIL, stroke: INK, "stroke-width": 2.5 }, svg); + txt(svg, 152, 91, "Comparisons", { "text-anchor": "middle", "font-size": 20, "font-weight": 700 }); + txt(svg, 64, 210, "Meta Muse", { "font-size": 84, "font-weight": 700 }); + txt(svg, 64, 300, "alternatives", { "font-size": 84, "font-weight": 700 }); + el("path", { d: "M66 328 H520", stroke: YEL, "stroke-width": 14, "stroke-linecap": "round" }, svg); + txt(svg, 64, 388, "7 picks, open source and hosted", { "font-size": 30, "font-weight": 500, fill: MUTE }); + txt(svg, 64, 478, "Checked 30 Oct 2026", { "font-family": MONO, "font-size": 18, "font-weight": 500, fill: MUTE }); + const g = el("g", {}, svg); tf(g, 770, 290); + compass(g, 112).setAttribute("transform", "rotate(38)"); + return () => {}; + }, + }; + + /* ---- 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/meta-muse-alternatives/sliders.png b/blog/src/assets/media/meta-muse-alternatives/sliders.png new file mode 100644 index 0000000000..3e14c27835 Binary files /dev/null and b/blog/src/assets/media/meta-muse-alternatives/sliders.png differ diff --git a/blog/src/assets/media/what-is-instinct-ai/bubbles.png b/blog/src/assets/media/what-is-instinct-ai/bubbles.png new file mode 100644 index 0000000000..4627c6b83d Binary files /dev/null and b/blog/src/assets/media/what-is-instinct-ai/bubbles.png differ diff --git a/blog/src/assets/media/what-is-instinct-ai/guestlist.png b/blog/src/assets/media/what-is-instinct-ai/guestlist.png new file mode 100644 index 0000000000..241f98bd61 Binary files /dev/null and b/blog/src/assets/media/what-is-instinct-ai/guestlist.png differ diff --git a/blog/src/assets/media/what-is-instinct-ai/hero.png b/blog/src/assets/media/what-is-instinct-ai/hero.png new file mode 100644 index 0000000000..3611feafeb Binary files /dev/null and b/blog/src/assets/media/what-is-instinct-ai/hero.png differ diff --git a/blog/src/assets/media/what-is-instinct-ai/mailboxes.png b/blog/src/assets/media/what-is-instinct-ai/mailboxes.png new file mode 100644 index 0000000000..11a35ec7ab Binary files /dev/null and b/blog/src/assets/media/what-is-instinct-ai/mailboxes.png differ diff --git a/blog/src/assets/media/what-is-instinct-ai/mixer.png b/blog/src/assets/media/what-is-instinct-ai/mixer.png new file mode 100644 index 0000000000..d64dcde6b5 Binary files /dev/null and b/blog/src/assets/media/what-is-instinct-ai/mixer.png differ diff --git a/blog/src/assets/media/what-is-instinct-ai/motion.css b/blog/src/assets/media/what-is-instinct-ai/motion.css new file mode 100644 index 0000000000..121f8af384 --- /dev/null +++ b/blog/src/assets/media/what-is-instinct-ai/motion.css @@ -0,0 +1,13 @@ +/* Bright coded scenes for "What is Instinct AI?". 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/what-is-instinct-ai/motion.js b/blog/src/assets/media/what-is-instinct-ai/motion.js new file mode 100644 index 0000000000..5cb701ae88 --- /dev/null +++ b/blog/src/assets/media/what-is-instinct-ai/motion.js @@ -0,0 +1,299 @@ +/* Bright coded scenes for "What is Instinct AI?". 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 RM = matchMedia("(prefers-reduced-motion: reduce)").matches; + 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 ring = (g, x, y, w, h, rx) => el("rect", { x, y, width: w, height: h, rx, fill: "none", stroke: INK, "stroke-width": 2, "stroke-dasharray": "4 6", class: "mg-ring" }, g); + const measure = (svg, s, a) => { const n = txt(svg, 0, -99, s, a), w = n.getComputedTextLength(); n.remove(); return w; }; + /* a toggle that eases over half a second, or snaps under reduced motion */ + const flip = (s, now) => { const p = RM ? 1 : seg(now - s.at, 0, 0.5); return s.on ? p : 1 - p; }; + const squashY = (n, cy, sy) => n.setAttribute("transform", `translate(0 ${cy}) scale(1 ${Math.max(sy, 0.001)}) translate(0 ${-cy})`); + const squashX = (n, cx, sx) => n.setAttribute("transform", `translate(${cx} 0) scale(${Math.max(sx, 0.001)} 1) translate(${-cx} 0)`); + const tickPath = (p, x, y, s = 1) => el("path", { d: `M${x - 7 * s} ${y} l${5 * s} ${5 * s} l${10 * s} ${-11 * s}`, stroke: INK, "stroke-width": 3, fill: "none", "stroke-linecap": "round", "stroke-linejoin": "round" }, p); + + const SC = {}; + + /* ---- 1. three messages fold into done cards ---- */ + SC.bubbles = { + dur: 8, still: 7, + build(svg, api) { + const root = el("g", {}, svg); + el("rect", { x: 240, y: 28, width: 320, height: 544, rx: 46, fill: "#fff", stroke: INK, "stroke-width": 3 }, root); + el("rect", { x: 360, y: 48, width: 80, height: 12, rx: 6, fill: SOFT, stroke: INK, "stroke-width": 2 }, root); + el("rect", { x: 264, y: 496, width: 272, height: 44, rx: 22, fill: SOFT, stroke: INK, "stroke-width": 2 }, root); + const R = 528, MSG = ["Book a train home", "Order groceries", "Send flowers"]; + let touched = false; + const msgs = MSG.map((s, i) => { + const cy = 170 + i * 110, g = el("g", {}, root); + const bw = measure(svg, s, { "font-size": 22 }) + 44, bx = R - bw, by = cy - 30; + const bub = el("g", {}, g); + el("path", { d: `M${bx + 24} ${by} H${R - 24} Q${R} ${by} ${R} ${by + 24} V${by + 54} Q${R} ${by + 60} ${R - 6} ${by + 60} H${bx + 24} Q${bx} ${by + 60} ${bx} ${by + 36} V${by + 24} Q${bx} ${by} ${bx + 24} ${by} Z`, fill: BLUE, stroke: INK, "stroke-width": 3 }, bub); + txt(bub, R - 22, cy + 8, s, { "font-size": 22, "text-anchor": "end" }); + const cw = measure(svg, s, { "font-size": 19 }) + 76, cx = R - cw; + const card = el("g", {}, g); + el("rect", { x: cx, y: cy - 24, width: cw, height: 48, rx: 14, fill: "#fff", stroke: INK, "stroke-width": 2.5 }, card); + el("circle", { cx: cx + 26, cy, r: 14, fill: MINT, stroke: INK, "stroke-width": 2 }, card); + tickPath(card, cx + 26, cy + 1, 0.8); + txt(card, cx + 50, cy + 7, s, { "font-size": 19 }); + ring(g, bx - 8, by - 8, bw + 16, 76, 28); + const st = { on: false, at: -99 }; + button(g, s, () => { touched = true; st.on = !st.on; st.at = api.now(); api.poke(); }); + return { g, bub, card, cy, st }; + }); + return (t, now) => { + const T = touched ? 7 : t; + root.setAttribute("opacity", 1 - seg(T, 7.6, 8)); + msgs.forEach((m, i) => { + const a = 0.4 + i, f = 3.4 + i * 0.6, app = ob(seg(T, a, a + 0.45)); + const k = touched ? 1 - flip(m.st, now) : io(seg(T, f, f + 0.6)); + m.g.setAttribute("opacity", seg(T, a, a + 0.15)); + m.g.setAttribute("transform", `translate(0 ${24 * (1 - app)})`); + squashY(m.bub, m.cy, k < 0.5 ? 1 - 2 * k : 0); + squashY(m.card, m.cy, k < 0.5 ? 0 : 2 * k - 1); + }); + }; + }, + }; + + /* ---- 2. a private beta guest list on a clipboard ---- */ + SC.guestlist = { + dur: 7, still: 6, + build(svg, api) { + const root = el("g", {}, svg); + const C = 290, board = el("g", {}, root); + el("rect", { x: 130, y: 64, width: 320, height: 490, rx: 26, fill: BLUE, stroke: INK, "stroke-width": 3 }, board); + const paper = el("g", {}, board); + el("rect", { x: 154, y: 112, width: 272, height: 418, rx: 12, fill: "#fff", stroke: INK, "stroke-width": 2.5 }, paper); + const p1 = el("g", {}, paper), p2 = el("g", {}, paper); + const title = el("g", {}, p1); + txt(title, C, 180, "Private beta", { "text-anchor": "middle", "font-size": 34, "font-weight": 700 }); + el("path", { d: `M${C - 96} 200 H${C + 96}`, stroke: YEL, "stroke-width": 8, "stroke-linecap": "round" }, title); + const rows = [["Invited", true], ["Invited", true], ["Waiting", false]].map(([s, ok], i) => { + const y = 270 + i * 80, g = el("g", {}, p1); + const box = el("rect", { x: 186, y: y - 22, width: 40, height: 40, rx: 8, fill: "#fff", stroke: INK, "stroke-width": 3 }, g); + const tk = ok ? tickPath(g, 206, y, 1.2) : null; + txt(g, 246, y + 10, s, { "font-size": 30 }); + el("path", { d: `M186 ${y + 36} H394`, stroke: SOFT, "stroke-width": 3, "stroke-linecap": "round" }, g); + return { g, box, tk, ok }; + }); + txt(p2, C, 300, "Price not", { "text-anchor": "middle", "font-size": 40, "font-weight": 700 }); + txt(p2, C, 352, "published", { "text-anchor": "middle", "font-size": 40, "font-weight": 700 }); + el("path", { d: `M${C - 90} 380 H${C + 90}`, stroke: LIL, "stroke-width": 8, "stroke-linecap": "round" }, p2); + el("rect", { x: 230, y: 40, width: 120, height: 50, rx: 14, fill: LIL, stroke: INK, "stroke-width": 3 }, board); + el("rect", { x: 266, y: 54, width: 48, height: 14, rx: 7, fill: "#fff", stroke: INK, "stroke-width": 2 }, board); + ring(board, 118, 28, 344, 538, 32); + const note = el("g", {}, root); + el("rect", { x: 0, y: 0, width: 190, height: 110, rx: 10, fill: SKY, stroke: INK, "stroke-width": 3 }, note); + el("rect", { x: 65, y: -12, width: 60, height: 22, rx: 4, fill: SOFT, stroke: INK, "stroke-width": 2 }, note); + txt(note, 95, 66, "18 or older", { "text-anchor": "middle", "font-size": 28, "font-weight": 700 }); + const st = { on: false, at: -99 }; + let touched = false; + button(board, "Private beta guest list", () => { touched = true; st.on = !st.on; st.at = api.now(); api.poke(); }); + return (t, now) => { + const T = touched ? 6 : t; + root.setAttribute("opacity", 1 - seg(T, 6.6, 7)); + const d = ob(seg(T, 0.1, 0.9)); + board.setAttribute("transform", `translate(0 ${-60 * (1 - d)})`); board.setAttribute("opacity", seg(T, 0.1, 0.3)); + p1.setAttribute("opacity", 1); + title.setAttribute("opacity", seg(T, 0.9, 1.3)); + rows.forEach((r, i) => { + const a = 1.3 + i * 0.5, k = oc(seg(T, a, a + 0.4)); + r.g.setAttribute("opacity", k); r.g.setAttribute("transform", `translate(${30 * (1 - k)} 0)`); + if (r.ok) { const p = ob(seg(T, a + 0.4, a + 0.75)); r.box.setAttribute("fill", p > 0.05 ? MINT : "#fff"); r.tk.setAttribute("opacity", p > 0.05 ? 1 : 0); r.tk.setAttribute("transform", `translate(206 ${270 + i * 80}) scale(${cl(p, 0, 1.3)}) translate(-206 ${-(270 + i * 80)})`); } + else { const w = seg(T, 3.0, 3.6); r.box.setAttribute("transform", `rotate(${Math.sin(w * Math.PI * 4) * 8 * (1 - w)} 206 ${270 + i * 80})`); } + }); + const n = oc(seg(T, 3.4, 4.1)); + note.setAttribute("opacity", seg(T, 3.4, 3.6)); note.setAttribute("transform", `translate(${500 + 80 * (1 - n)} 170) rotate(${4 + 10 * (1 - n)})`); + const f = touched ? flip(st, now) : 0; + squashX(paper, C, Math.abs(Math.cos(f * Math.PI))); + p1.setAttribute("display", f < 0.5 ? "inline" : "none"); p2.setAttribute("display", f < 0.5 ? "none" : "inline"); + }; + }, + }; + + /* ---- 3. a mixing desk: one slider up, one held down ---- */ + SC.mixer = { + dur: 7, still: 6, + build(svg, api) { + const root = el("g", {}, svg); + el("rect", { x: 70, y: 20, width: 660, height: 476, rx: 28, fill: SOFT, stroke: INK, "stroke-width": 3 }, root); + const TOP = 170, BOT = 320, LY = [108, 376]; + const ch = [ + { c: 230, name: "Your messages and use", lamp: "Used to train models", up: true, col: YEL }, + { c: 570, name: "Google Workspace data", lamp: "Not used to train", up: false, col: MINT }, + ]; + let sel = -1, selAt = -99, touched = false; + ch.forEach((s, i) => { + const g = el("g", {}, root), ly = LY[i], lt = s.up ? 66 : 432; + el("rect", { x: s.c - 8, y: TOP - 10, width: 16, height: BOT - TOP + 20, rx: 8, fill: "#fff", stroke: INK, "stroke-width": 2.5 }, g); + s.fill = el("rect", { x: s.c - 8, y: BOT, width: 16, height: 10, rx: 8, fill: BLUE, stroke: INK, "stroke-width": 2.5 }, g); + for (let k = 0; k <= 4; k++) { const y = TOP + (k * (BOT - TOP)) / 4; el("path", { d: `M${s.c - 54} ${y} H${s.c - 34} M${s.c + 34} ${y} H${s.c + 54}`, stroke: INK, "stroke-width": 2.5, "stroke-linecap": "round" }, g); } + s.rays = el("g", { opacity: 0 }, g); + for (let k = 0; k < 8; k++) { const a = ((k + 0.5) / 8) * Math.PI * 2; el("path", { d: `M${s.c + Math.cos(a) * 24} ${ly + Math.sin(a) * 24} L${s.c + Math.cos(a) * 32} ${ly + Math.sin(a) * 32}`, stroke: INK, "stroke-width": 3, "stroke-linecap": "round" }, s.rays); } + s.bulb = el("circle", { cx: s.c, cy: ly, r: 18, fill: "#fff", stroke: INK, "stroke-width": 3 }, g); + txt(g, s.c, lt, s.lamp, { "text-anchor": "middle", "font-size": 22 }); + txt(g, s.c, 474, s.name, { "text-anchor": "middle", "font-size": 22, "font-weight": 700 }); + s.knob = el("g", {}, g); + el("rect", { x: -38, y: -16, width: 76, height: 32, rx: 9, fill: "#fff", stroke: INK, "stroke-width": 3 }, s.knob); + el("path", { d: "M-22 0 H22", stroke: INK, "stroke-width": 3, "stroke-linecap": "round" }, s.knob); + ring(g, s.c - 150, 32, 300, 456, 22); + button(g, `${s.name}: ${s.lamp}`, () => { touched = true; sel = i; selAt = api.now(); api.poke(); }); + }); + const card = el("g", {}, svg); + el("rect", { x: 110, y: 508, width: 580, height: 84, rx: 22, fill: "#fff", stroke: INK, "stroke-width": 2.5 }, card); + txt(card, 400, 542, "Privacy policy, read 30 Oct 2026", { "text-anchor": "middle", "font-size": 20, "font-weight": 500, fill: MUTE }); + const line = txt(card, 400, 574, "", { "text-anchor": "middle", "font-size": 24, "font-weight": 700 }); + return (t, now) => { + const T = touched ? 6 : t; + root.setAttribute("opacity", 1 - seg(T, 6.6, 7)); + ch.forEach((s, i) => { + const v = s.up ? io(seg(T, 1.0, 3.0)) : 0, y = BOT - (BOT - TOP) * v; + tf(s.knob, s.c, y); s.fill.setAttribute("y", y); s.fill.setAttribute("height", BOT + 10 - y); + const lit = s.up ? seg(T, 2.9, 3.1) : seg(T, 3.5, 3.7), pop = ob(lit); + s.bulb.setAttribute("fill", lit > 0.5 ? s.col : "#fff"); + s.rays.setAttribute("opacity", lit > 0.5 ? 1 : 0); + s.rays.setAttribute("transform", `translate(${s.c} ${LY[i]}) scale(${0.6 + 0.4 * cl(pop, 0, 1.2)}) translate(${-s.c} ${-LY[i]})`); + }); + const k = sel < 0 ? 0 : RM ? 1 : oc(seg(now - selAt, 0, 0.35)); + card.setAttribute("opacity", k); card.setAttribute("transform", `translate(0 ${16 * (1 - k)})`); + line.textContent = sel < 0 ? "" : ch[sel].lamp; + }; + }, + }; + + /* ---- 4. six mailboxes, six ways in ---- */ + SC.mailboxes = { + dur: 8, still: 7, + build(svg, api) { + const root = el("g", {}, svg); + const BOX = [ + ["Poke", ["Text"], "No price in list", SKY, YEL], + ["Munder Difflin", ["Desktop", "and Slack"], "Free, open source", YEL, BLUE], + ["Folk", ["iMessage"], "Free, Pro $8.33 a month", LIL, YEL], + ["Martin", ["SMS and", "phone"], "From $21 a month", MINT, LIL], + ["Comma", ["Signal and", "Telegram"], "Free to start, open source", BLUE, YEL], + ["Maverick", ["iMessage"], "Free beta, Pro €27 a month", SKY, LIL], + ]; + const G = 352; + el("path", { d: `M30 ${G} H770`, stroke: INK, "stroke-width": 3, "stroke-linecap": "round" }, root); + let sel = -1, selAt = -99, touched = false; + const boxes = BOX.map(([name, tag, price, body, flag], i) => { + const cx = 72 + i * 125, g = el("g", {}, root), up = el("g", {}, g); + const nm = name.split(" "); + nm.forEach((w, j) => txt(up, cx, 150 - (nm.length - 1 - j) * 22, w, { "text-anchor": "middle", "font-family": MONO, "font-size": 18, "font-weight": 700 })); + el("rect", { x: cx - 7, y: 262, width: 14, height: G - 262, fill: "#fff", stroke: INK, "stroke-width": 3 }, up); + const fl = el("g", {}, up); + el("path", { d: `M0 0 V-40`, stroke: INK, "stroke-width": 3.5, "stroke-linecap": "round" }, fl); + el("path", { d: "M0 -40 H22 L16 -32 L22 -24 H0 Z", fill: flag, stroke: INK, "stroke-width": 2.5, "stroke-linejoin": "round" }, fl); + el("path", { d: `M${cx - 36} 264 V212 A36 36 0 0 1 ${cx + 36} 212 V264 Z`, fill: body, stroke: INK, "stroke-width": 3, "stroke-linejoin": "round" }, up); + el("path", { d: `M${cx - 16} 214 H${cx + 16}`, stroke: INK, "stroke-width": 4, "stroke-linecap": "round" }, up); + el("circle", { cx: cx + 36, cy: 238, r: 4, fill: INK }, up); + const tg = el("g", {}, g), tb = el("rect", { x: cx - 56, y: 372, width: 112, height: 60, rx: 14, fill: "#fff", stroke: INK, "stroke-width": 2.5 }, tg); + tag.forEach((w, j) => txt(tg, cx, 408 + (j - (tag.length - 1) / 2) * 21, w, { "text-anchor": "middle", "font-size": 17, "font-weight": 600 })); + ring(g, cx - 61, 108, 122, 330, 18); + button(g, `${name}: ${tag.join(" ")}. ${price}`, () => { touched = true; sel = i; selAt = api.now(); api.poke(); }); + return { cx, up, fl, tg, tb, g }; + }); + const card = el("g", {}, svg); + el("rect", { x: 100, y: 478, width: 600, height: 72, rx: 24, fill: SOFT, stroke: INK, "stroke-width": 2.5 }, card); + const line = txt(card, 400, 522, "", { "text-anchor": "middle", "font-size": 24 }); + const ln = el("tspan", { "font-family": MONO, "font-weight": 700 }, line), lp = el("tspan", { "font-weight": 500, dx: 14 }, line); + return (t, now) => { + const T = touched ? 7 : t; + root.setAttribute("opacity", 1 - seg(T, 7.6, 8)); + boxes.forEach((b, i) => { + const a = 0.2 + i * 0.15, k = ob(seg(T, a, a + 0.5)); + b.up.setAttribute("opacity", seg(T, a, a + 0.1)); + b.up.setAttribute("transform", `translate(0 ${G}) scale(1 ${Math.max(k, 0.001)}) translate(0 ${-G})`); + const f = 1.6 + i * 0.55, r = ob(seg(T, f, f + 0.45)); + b.fl.setAttribute("transform", `translate(${b.cx + 40} 248) rotate(${90 - 90 * r})`); + const q = oc(seg(T, f + 0.1, f + 0.45)); + b.tg.setAttribute("opacity", q); b.tg.setAttribute("transform", `translate(0 ${-14 * (1 - q)})`); + b.tb.setAttribute("fill", i === sel ? YEL : "#fff"); + }); + const k = sel < 0 ? 0 : RM ? 1 : oc(seg(now - selAt, 0, 0.35)); + card.setAttribute("opacity", k); card.setAttribute("transform", `translate(0 ${16 * (1 - k)})`); + if (sel >= 0) { ln.textContent = BOX[sel][0]; lp.textContent = BOX[sel][2]; } + }; + }, + }; + + /* ---- title card, 16 by 9 ---- */ + SC.hero = { + w: 960, h: 540, dur: 1, still: 0, + build(svg) { + el("rect", { x: 64, y: 84, width: 132, height: 38, rx: 19, fill: YEL, stroke: INK, "stroke-width": 2.5 }, svg); + txt(svg, 130, 110, "Concepts", { "text-anchor": "middle", "font-size": 19, "font-weight": 700 }); + txt(svg, 64, 222, "What is", { "font-size": 76, "font-weight": 700 }); + txt(svg, 64, 306, "Instinct AI?", { "font-size": 76, "font-weight": 700 }); + el("path", { d: "M66 334 H420", stroke: LIL, "stroke-width": 14, "stroke-linecap": "round" }, svg); + txt(svg, 64, 392, "Private beta, plus 6 alternatives", { "font-size": 27, "font-weight": 500, fill: MUTE }); + txt(svg, 64, 446, "Checked 30 Oct 2026", { "font-family": MONO, "font-size": 18, "font-weight": 500, fill: MUTE }); + const bub = (x, y, w, col, right) => { + const h = 70, r = 26, g = el("g", {}, svg); + const d = right + ? `M${x + r} ${y} H${x + w - r} Q${x + w} ${y} ${x + w} ${y + r} V${y + h - 6} Q${x + w} ${y + h} ${x + w - 6} ${y + h} H${x + r} Q${x} ${y + h} ${x} ${y + h - r} V${y + r} Q${x} ${y} ${x + r} ${y} Z` + : `M${x + r} ${y} H${x + w - r} Q${x + w} ${y} ${x + w} ${y + r} V${y + h - r} Q${x + w} ${y + h} ${x + w - r} ${y + h} H${x + 6} Q${x} ${y + h} ${x} ${y + h - 6} V${y + r} Q${x} ${y} ${x + r} ${y} Z`; + el("path", { d, fill: col, stroke: INK, "stroke-width": 3 }, g); + return g; + }; + bub(640, 136, 210, LIL, false); + [0, 1, 2].forEach((k) => el("circle", { cx: 690 + k * 26, cy: 171, r: 7, fill: INK }, svg)); + bub(660, 238, 236, BLUE, true); + el("rect", { x: 688, y: 262, width: 150, height: 10, rx: 5, fill: "#fff" }, svg); + el("rect", { x: 688, y: 282, width: 96, height: 10, rx: 5, fill: "#fff" }, svg); + bub(640, 340, 196, SKY, false); + el("circle", { cx: 680, cy: 375, r: 16, fill: MINT, stroke: INK, "stroke-width": 2.5 }, svg); + tickPath(svg, 680, 376, 0.9); + el("rect", { x: 708, y: 370, width: 100, height: 10, rx: 5, fill: "#fff" }, svg); + return () => {}; + }, + }; + + /* ---- player ---- */ + const q = new URLSearchParams(location.search), frozen = q.has("mgstill"), fixed = parseFloat(q.get("mgstill")); + const calm = RM; + 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/posts/agent-tools-today-2026-10-30.md b/blog/src/posts/agent-tools-today-2026-10-30.md new file mode 100644 index 0000000000..30e55f4efd --- /dev/null +++ b/blog/src/posts/agent-tools-today-2026-10-30.md @@ -0,0 +1,57 @@ +--- +title: "Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App" +seoTitle: "Agent Tools Today (30 Oct 2026): Launches, Skills, MCP Servers" +description: "The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date." +date: 2026-10-30 +category: news +categoryLabel: News +type: Non-technical +series: agent-tools-today +primaryKeyword: "agent tools today 30 oct 2026" +secondaryKeywords: ["mistral large 4 weights", "claude code 2.1.314", "herdr desktop app", "codex 0.166.0", "opencode 2.2.2", "qwenputer"] +tags: ["Daily Brief", "Claude Code", "Skills", "Open Source"] +--- + +Agent tools today, 30 Oct 2026, in one line: Mistral released the weights of Mistral Large 4, Claude Code 2.1.314 can refuse every write outside your working folders, and Herdr shipped a desktop app for terminals and coding agents. It covers 29 to 30 Oct, checked 30 Oct. An earlier edition is [26 Oct](/blog/agent-tools-today-2026-10-26/). + +[Munder Difflin](https://harnessmd.com/download) is free and open source: a desktop app that runs a team of AI agents for all kinds of knowledge work, coding included, on your own computer. It is not ranked in the lists below. + +
Animation. On a white background, three envelopes drop one at a time into the slots of a mail sorting rack. The first reads Mistral Large 4 with a tag Weights out, the second Claude Code 2.1.314 with a tag Write guard, and the third Herdr with a tag Desktop app. Tapping an envelope slides it out of its slot or back in.
The day's three lead items, from Mistral's release post, Claude Code's release notes and Herdr's README, read 30 Oct 2026.
+ +## Top 3 launches + +1. **Mistral Large 4 weights.** On 29 Oct Mistral put the weights on Hugging Face under the Mistral Ecosystem Open-Weight license, which its post calls "a modified MIT license". The post prices the API at $0.70 per million input tokens and $2.10 per million output tokens on 29 Oct 2026. More than 1,250 points on Hacker News on 30 Oct. Details in [Mistral Large 4](/blog/mistral-large-4/). [Source](https://mistral.ai/news/mistral-large-4-oss/) +2. **Qwenputer.** A stock Qwen 3.5 4B model with a RISC-V CPU compiled into its weights, using the model's Gated DeltaNet layers as memory. Its write up says it runs arithmetic, C and MicroPython inside the forward pass "without any external runtime or tool usage", and calls it "a pretty fun experimental model". More than 680 points on Hacker News on 30 Oct. [Source](https://divagr.com/blog/qwenputer) +3. **Herdr desktop app.** Herdr now has "a desktop app for terminals and coding agents": spaces for work, a status for each agent (working, blocked, done or idle), and terminals that keep running when you close the window. Builds for Linux, Apple Silicon Macs and Windows, Apache 2.0, more than 210 stars on 30 Oct. See [Herdr alternatives](/blog/herdr-alternatives/). [Source](https://github.com/herdrdev/herdr-app) + +## Top 3 skills, MCP servers and plugins + +1. **AI Design Skills.** A collection of design skills for Claude Code, Cursor, Codex, Windsurf "and anything else that reads a markdown rules file". The first, `landing-page-design`, builds a landing page from intake questions to a full visual system. MIT, more than 12,000 stars, and 1,187 stars in a day on GitHub trending on 30 Oct. [Source](https://github.com/elayadesign/ai-design-skills) +2. **MiniMax mcode-stack.** "The workflows and skills the MiniMax Code team uses to build MiniMax Code", each a `SKILL.md` skill or checklist, among them a check for whether work should go to a subagent and an audit of what tools cost in context. MIT, created 28 Oct, more than 420 stars on 30 Oct. [Source](https://github.com/MiniMax-AI/mcode-stack) +3. **Grim Prompter.** A threat modeling skill: point Claude Code, Codex or another coding agent at a repo and get a threat model traced to the code, from 36 architecture workflows and 29 method and analysis prompts. MIT, created 28 Oct, more than 160 stars on 30 Oct. [Source](https://github.com/jmanico/grim-prompter) + +## Top 3 moves from multi agent tools + +1. **Claude Code 2.1.314.** Published 30 Oct. A new `permissions.blockWritesOutsideWorkingDirectories` setting makes Write, Edit and NotebookEdit refuse paths outside the working folders in every permission mode. VS Code and the Claude Desktop Code tab now summarize a 200K+ token conversation left idle, and sessions no longer fail turn after turn when an admin caps a model's effort. See [Claude Code alternatives](/blog/claude-code-alternatives/). [Source](https://github.com/anthropics/claude-code/releases/tag/v2.1.314) +2. **Codex 0.166.0.** Published 29 Oct. It adds keyboard driven transcript selection with search, GPT-6.1 Terra in the bundled, Vertex AI and Amazon Bedrock model catalogs, `codex queue --resume`, and `codex doctor --network-only` for connection checks. [Source](https://github.com/openai/codex/releases/tag/rust-v0.166.0) +3. **OpenCode 2.2.2.** Published 29 Oct. Agents can now generate images by default when a connected provider has an image model, and clicking the current Git branch on the new session screen opens the worktree picker. See [OpenCode alternatives](/blog/opencode-alternatives/). [Source](https://github.com/anomalyco/opencode/releases/tag/v2.2.2) + +## Top 3 rising repos + +1. **OpenMausBot.** It calls itself "The open-source Grok Bot alternative: your own team of AI bots, in a chat app", where each bot is Claude or Codex running locally with its own model and connected apps. Apache 2.0, more than 7,500 stars, and 1,199 stars in a day on GitHub trending on 30 Oct. See [Grok Bot alternatives](/blog/grok-bot-alternatives/). [Source](https://github.com/milind-soni/OpenMausBot) +2. **ThinkRail.** A JetBrains incubator IDE built around the `pi` coding agent, with work isolated in git worktrees, specs kept beside the code, and Agent Skills from other coding agents read in. Apache 2.0, more than 6,000 stars, and 1,117 stars in a day on GitHub trending on 30 Oct. [Source](https://github.com/JetBrains/thinkrail) +3. **BLA.** "Blind LLM Agents", a defensive tool that hardens software you ship so an AI reverse engineering agent hits resource budgets and follows decoys, while users see the same behavior. MIT, created 25 Oct, more than 890 stars on 30 Oct. [Source](https://github.com/qybaihe/bla) + +Stars can rise for reasons other than use: names to watch, not picks. + +## Top 3 things people are arguing about + +1. **Can readers tell when an LLM wrote a post?** In "LLM Voice" on 29 Oct, Martin Fowler writes that he urges authors "to be extra-wary of LLM-Voice" and not to have a model write a draft, since even after a human edits it, LLM Voice is very hard to remove. His site asks anyone who uses AI to help write to say how. More than 370 points on Hacker News on 30 Oct. [Source](https://martinfowler.com/bliki/LLM-Voice.html) +2. **Where do the numbers AI assistants quote come from?** Trakkr traced 1,285 statistics cited by five AI assistants, published 28 Oct. 40% reached a study that says the same thing, 8% reached the study with the number changed, 40% stopped at a source it could not check, and 11% led nowhere. More than 150 points on Hacker News on 30 Oct. [Source](https://trakkr.ai/trakkr-research/zombie-stats) +3. **What are agents doing to GitHub?** The New Stack reported on 28 Oct that GitHub now sees 7.4 billion commits a month, up from 2.9 billion in August, and has added 4 million CPU cores this year. GitHub puts the growth down mostly to "agentic demand". More than 45 points on Hacker News on 30 Oct. [Source](https://thenewstack.io/github-7-4b-commits-september/) + +## How this list is built + +For this edition, covering 29 to 30 Oct, we read the GitHub releases of 16 tracked tools, vendor blogs and changelogs, GitHub trending, and the Hacker News front page. We did not read X or Reddit for it. A name only makes a list with a link that was opened and a signal that can be shown: points, stars or a dated release. Repos are checked against the GitHub API before they appear. New here? Start with the [install guide](/blog/how-to-install-and-use-munder-difflin/). + + diff --git a/blog/src/posts/meta-muse-alternatives.md b/blog/src/posts/meta-muse-alternatives.md index dbe85d1cce..5b465b47cf 100644 --- a/blog/src/posts/meta-muse-alternatives.md +++ b/blog/src/posts/meta-muse-alternatives.md @@ -1,117 +1,100 @@ --- -title: "Meta Muse Alternatives: 7 Picks for People Who Can't (or Won't) Use Muse" -seoTitle: "7 Best Meta Muse Alternatives in 2026 (Free and Open Source)" -description: "Meta Muse is US only and trains on your chats by default. Seven alternatives, from open source agents that run on your own computer to hosted ones from OpenAI, Google and SpaceXAI." +title: "Meta Muse Alternatives: 7 Picks If Muse Isn't in Your Country or You Want Your Data Back (Oct 2026)" +seoTitle: "7 Best Meta Muse Alternatives (Oct 2026): Free and Open Source" +description: "Meta Muse is in the US and Canada and trains on your chats by default. Seven alternatives, open source and hosted, with access and plans checked 30 Oct 2026." date: 2026-09-26 +updated: 2026-10-30 category: comparisons categoryLabel: Comparisons type: Non-technical primaryKeyword: "meta muse alternatives" secondaryKeywords: ["meta muse alternative", "open source meta muse alternative", "free meta muse alternative", "meta muse not available in my country", "apps like meta muse", "meta muse competitors"] tags: ["Comparisons", "AI Agents", "Open Source", "Local-First"] -ogImage: "https://munderdiffl.in/blog/assets/media/meta-muse-alternatives/lead-still.png" +ogImage: "https://munderdiffl.in/blog/assets/media/meta-muse-alternatives/hero.png" author: name: Chaitanya Giri initials: CG faq: - q: "Why can't I use Meta Muse?" - a: "At launch on 8 September 2026 Muse was open only to people in the US aged 18 and over. Meta says more countries will be added over time but has not given dates." + a: "Muse launched in the US on 8 September 2026, and iPhone in Canada reported it reached Canada on 18 September. RuntimeWire reported on 23 October that a Meta executive said it was launching in Japan. Meta has not published a full country list or dates for other countries." - q: "Is there an open source alternative to Meta Muse?" - a: "Yes. OpenClaw is the closest: an open source personal assistant that runs on your own computer and replies in WhatsApp, Telegram, Slack, iMessage and more. For work agents rather than errands, Munder Difflin is free and open source and runs a team of agents on your machine." + a: "Yes. OpenClaw is the closest: an open source assistant, MIT licensed, that runs on your own computer and replies in WhatsApp, iMessage, Telegram, Slack and more than 20 other channels. Munder Difflin is a free and open source desktop app for a team of agents, and Hermes Agent and OpenMausBot are open source too." - q: "Does Meta Muse train on my data?" - a: "By default, yes. Meta's help page says Muse conversations can be used to train its models unless you turn that off in Settings, and that Meta removes details like names, emails and phone numbers first. Meta says Muse does not share your chats or VM data with its ad systems." + a: "By default, yes. Meta's help page, read 30 Oct 2026, says the setting that lets Meta use your Muse interactions to improve its models is on when you first use Muse, and you can turn it off in Settings under Data controls. Meta says Muse does not share your conversations or VM data with its ad systems." - q: "What is the best free alternative to Meta Muse?" - a: "For personal errands, OpenClaw and Hermes Agent are free and open source; you pay only for the AI model, or nothing with a local one. For work agents, Munder Difflin is free and uses the AI engines you already have." -thumb: "/blog/assets/media/meta-muse-alternatives/lead-still.png" + a: "OpenClaw, Munder Difflin, Hermes Agent and OpenMausBot are free and open source. With OpenClaw, Hermes Agent and OpenMausBot you pay only for the AI model you connect; Munder Difflin uses engines such as Claude Code, Codex and Gemini CLI. Checked 30 Oct 2026." --- -
TL;DR

For a personal assistant you own, try OpenClaw. For a team of work agents on your own computer, try Munder Difflin. For a hosted assistant from a big lab, try ChatGPT Work, Gemini Spark, Grok Bot or Claude Cowork. For memory that grows with you, try Hermes Agent.

+Our view: the best Meta Muse alternative depends on why you are leaving. Outside Muse's countries, start with OpenClaw, an open source assistant on your own computer. For a team of agents on your work, try Munder Difflin. For a hosted agent, Grok Bot, Gemini tasks and Claude Cowork are closest. Checked 30 Oct 2026. -Meta Muse is one of the most talked about launches of the year. Within two weeks of its 8 September release, [CNBC reported](https://www.cnbc.com/2026/09/21/meta-muse-personal-ai-agent-downloads.html) the Muse app ranking ahead of ChatGPT on Apple's App Store. +[Munder Difflin](https://harnessmd.com/download) is free and open source: a desktop app that runs a team of AI agents for all kinds of knowledge work, coding included, on your own computer. This page sits in our [Comparisons hub](/blog/topics/comparisons/). -Plenty of people still can't use it, or don't want to. There are three common reasons: +## Why look for a Meta Muse alternative? -- **You live outside the US.** Muse launched for US users aged 18 and over only. -- **You don't want Meta holding your inbox, calendar and bank data.** Muse trains on your chats by default unless you switch it off, according to [Meta's own help page](https://www.meta.com/help/artificial-intelligence/1047255454427887/). A WIRED reporter also found it [kept asking for more personal data](https://techbriefly.com/2026/09/21/meta-muse-ai-data-collection-scrutiny/). -- **You want agents for your work, not your errands.** Muse is built for bookings, forms and shopping, not for writing code or running projects. For Meta's coding agent, see [Muse Code and Muse Wonder](/blog/muse-wonder/). Or read [Muse Code vs Claude Code](/blog/muse-code-vs-claude-code/). +Three reasons come up most. -Here are seven alternatives, and which reason each one solves. +- **Muse is not in your country.** Meta's [launch post](https://about.fb.com/news/2026/09/introducing-muse/) of 8 Sep 2026 says Muse "is rolling out in the US". [iPhone in Canada](https://www.iphoneincanada.ca/2026/09/18/metas-muse-ai-agent-is-now-available-in-canada/) reported it reached Canada on 18 Sep, and [RuntimeWire](https://runtimewire.com/article/meta-muse-japan-launch-wang) reported that a Meta executive said it was launching in Japan on 23 Oct. +- **You don't want Meta training on your chats.** Meta's [help page](https://www.meta.com/help/artificial-intelligence/1047255454427887/), read 30 Oct 2026, says the training setting "is on when you first use Muse". You can switch it off under Settings, Data controls. +- **You want agents for your work.** Meta's launch post gives sending an email or booking travel as examples of what Muse does. For Meta's coding agent, see [Muse Code vs Claude Code](/blog/muse-code-vs-claude-code/). -
Muse is US only for now. Three of the seven alternatives run on your own computer.
- - +
Animation. On a white background, a simple globe turns and three pins drop one at a time: US with the date 8 Sep, Canada with 18 Sep, and Japan with 23 Oct and a small note Reported. The rest of the globe stays plain. Tapping a pin shows its source.
Meta's launch post of 8 Sep 2026, iPhone in Canada on 18 Sep, and RuntimeWire on 23 Oct for Japan.
-## The seven alternatives at a glance +## What are the best Meta Muse alternatives? + +Seven, checked on 30 Oct 2026. | Alternative | Best for | Where it runs | Cost | | --- | --- | --- | --- | | OpenClaw | A personal assistant you own | Your computer | Free, open source | -| Munder Difflin | A team of work agents | Your computer | Free, open source | -| ChatGPT Work | Work inside ChatGPT | OpenAI's cloud and your desktop | Part of ChatGPT plans | -| Gemini Spark | Gmail, Drive and Calendar users | Google's cloud | Google AI Pro and Ultra | -| Grok Bot | Hosted agent teammates | Cursor's cloud, in the US | Plans from $20 a month | -| Claude Cowork | Work in your own folders | Anthropic's servers by default | Paid Claude plan | -| Hermes Agent | Memory that learns | Your laptop or a small server | Free, open source | - -Facts for the hosted products and the open source projects were checked on their official pages and GitHub repos in September 2026. +| Munder Difflin | A team of agents for your work | Your computer | Free, open source | +| Grok Bot | Hosted bots that keep working | One cloud computer per account | Premium, Super or Ultra on The X Subscription | +| Gemini tasks | Gmail, Drive and Calendar users | Google's cloud and your Chrome | Google AI Pro or Ultra | +| Claude Cowork | Documents, files and research | Anthropic's cloud, with local files on desktop | Paid Claude plan | +| Hermes Agent | Memory that learns | Your laptop, a server or a sandbox | Free, open source | +| OpenMausBot | A chat app of local bots | Your computer | Free, open source | ## 1. OpenClaw: the closest thing to Muse that you own -[OpenClaw](https://github.com/openclaw/openclaw) is an open source personal assistant (MIT licence) that runs on your own computer. Like Muse inside WhatsApp, it replies where you already chat: WhatsApp, Telegram, Slack, iMessage and more than 20 other channels. Your state, memory and logins stay on your hardware, and you can swap models freely, local ones included. There is no paid tier. - -**Solves:** the US only limit and the data worry. -**The catch:** by default tools run straight on your machine, so set up sandboxing before you hand it your accounts. - -## 2. Munder Difflin: a team of work agents on your own computer - -[Munder Difflin](https://harnessmd.com/download) is what we make, and it answers the third reason. It will not book your travel. It gives you an office of AI agents for real work, mostly engineering: each agent is a terminal session running an engine you choose, such as Claude Code, Codex, Gemini CLI, Cursor or Grok's own CLI, or a local model through Ollama. - -Each agent gets a desk, an inbox, memory in plain markdown files and a shared task board. You can start work from Slack or a webhook, schedule missions, and talk to one lead agent instead of twelve. A circuit breaker stops any agent that loops or overspends. It runs on macOS, Windows and Linux, in any country, and it is free and open source. +[OpenClaw](https://github.com/openclaw/openclaw) is "an open-source AI assistant that runs on your own computer", MIT licensed, with more than 390,000 stars on 30 Oct 2026. It replies in Discord, iMessage, Slack, Teams, Telegram, WhatsApp "and 20+ more". The catch, per its README: tools run on the host "unless you configure sandboxing", so set that up first. -**Solves:** all three reasons, if your need is work rather than errands. -**The catch:** agents run while your computer runs. For overnight work, keep a machine awake, like a [Mac mini on your desk](/blog/run-munder-difflin-on-a-mac-mini/). +## 2. Munder Difflin: a team of agents for your work -For how it compares with OpenAI's new always on agents, read [ChatGPT dots vs Munder Difflin](/blog/munder-difflin-vs-chatgpt-dots/). +[Munder Difflin](https://harnessmd.com/download) is what we make. It runs a team of agents for research, writing, ops and coding on engines such as Claude Code, Codex and Gemini CLI. Each agent has its own memory and inbox, and they share a task board. Work comes in from Slack and webhooks, and tools connect through MCP servers, skills and plugins. A Cloud Office and a mobile app are coming soon. The catch: agents run while your computer runs. -## 3. ChatGPT Work: the hosted pick for work +## 3. Grok Bot: hosted bots that keep working -ChatGPT Work is OpenAI's agent inside ChatGPT. Plugins connect it to Slack, Microsoft Teams, Google Drive, email and calendars. Scheduled Tasks run on a timer or when something happens, and you decide what needs your approval. In the Mac and Windows desktop app it can also work with your local files. It is available in the countries OpenAI supports. +[Grok Bot's plans page](https://cursor.com/help/grok-bot/plans), read 30 Oct 2026, says it is included on Premium, Super and Ultra in The X Subscription, and on paid legacy Cursor plans. Its [FAQ](https://docs.x.ai/grok-bot/faq) says every Bot on an account shares "one persistent cloud computer", and closing your laptop does not stop a background turn. See [Meta Muse vs Grok Bot](/blog/meta-muse-vs-grok-bot/). -**Solves:** the US only limit. -**The catch:** your work runs through OpenAI's cloud, and you need a ChatGPT plan that includes it. +## 4. Gemini tasks: for people who live in Google -OpenAI added always on agents called dots on 29 Sep 2026, on Pro and Business Premium only. If those are out of reach too, see [ChatGPT dots alternatives](/blog/chatgpt-dots-alternatives/). +Google renamed Gemini Spark. Its [help page](https://support.google.com/gemini/answer/17094507), read 30 Oct 2026, says: "we renamed it Task to make it easier to understand." Tasks need a Google AI Pro or Ultra plan, a personal Google Account and an age of 18 or over, Keep Activity on and Personal Intelligence turned on, and for now are not available in the European Economic Area, Nigeria, Switzerland or the United Kingdom. -## 4. Gemini Spark: for people who live in Google +## 5. Claude Cowork: for documents, files and research -Gemini Spark suits you if your life already runs on Gmail, Drive and Calendar. Google says it keeps working with your phone and laptop off and checks with you before major actions. It comes with Google AI Pro and Ultra in select countries, plus select business users. +Anthropic's [Cowork guide](https://support.claude.com/en/articles/13345190-get-started-with-cowork), read 30 Oct 2026, lists it on the paid Pro, Max, Team and Enterprise plans. It "runs your sessions remotely in the cloud", keeps working when you close your laptop, and on desktop can read and write your local files. -**Solves:** the US only limit, in the countries Google has opened. -**The catch:** you are trading one big tech company for another. +## 6. Hermes Agent: for memory that grows -## 5. Grok Bot: hosted teammates for your job +[Hermes Agent](https://github.com/NousResearch/hermes-agent) from Nous Research is MIT licensed. Its README says it creates skills from experience, curates its own memory and talks over Telegram, Discord, Slack, WhatsApp and Signal. You pick the model provider and can switch with `hermes model`. -Grok Bot from SpaceXAI is the most direct rival to Muse, aimed at work instead of errands. Bots sign into your apps through a normal browser, hand jobs to each other and keep going with your laptop shut. It comes with SuperGrok and paid Cursor plans, starting at $20 a month. All the Bots on your account share one cloud computer in the US. See our [Meta Muse vs Grok Bot comparison](/blog/meta-muse-vs-grok-bot/) for the full picture. +## 7. OpenMausBot: a chat app of local bots -**Solves:** the work reason. -**The catch:** there is no model picker, and your data lives on US cloud computers. +[OpenMausBot](https://github.com/milind-soni/OpenMausBot) calls itself "The open-source Grok Bot alternative", and its README also names it an alternative to Meta Muse. Each bot is Claude or Codex running locally, with its own model and connected apps. Apache 2.0, and on GitHub trending on 30 Oct 2026. -## 6. Claude Cowork: for work in your own folders +Two more to watch: [Instinct](/blog/what-is-instinct-ai/), a texting agent still in private beta, and OpenAI's dots, covered in [ChatGPT dots alternatives](/blog/chatgpt-dots-alternatives/). -[Claude Cowork](https://support.claude.com/en/articles/13345190-get-started-with-cowork) needs a paid Claude plan. In the macOS or Windows desktop app, Claude works only inside the folders you choose and asks before deleting anything. By default the work runs on Anthropic's servers, which makes it closer to Muse than it looks, with a tighter fence around your files. +
Animation. On a white background, a settings panel titled Muse shows one switch labelled Use my interactions to improve models. It starts On. A second line reads Settings, Data controls, and the switch slides to Off. Tapping the switch turns it back on or off.
Meta's help page, read 30 Oct 2026: the training setting is on when you first use Muse, and you can turn it off under Data controls.
-**Solves:** the work reason, and part of the data worry. -**The catch:** it is still a hosted service. +## How do you choose? -## 7. Hermes Agent: for memory that grows +Start from the reason you are leaving. -[Hermes Agent](https://github.com/NousResearch/hermes-agent) from Nous Research is open source (MIT). It curates its own memory, writes new skills after hard tasks and runs scheduled jobs. You talk to it over Telegram, Discord, Slack, WhatsApp or Signal. It can live on your laptop or a cheap server, and one command switches between model providers. +- **Muse is not in your country.** OpenClaw or Hermes Agent, both open source on your own hardware. +- **You don't want your chats used for training.** An open source pick with a model provider you choose, and read that provider's terms. +- **You want agents for your work.** Claude Cowork if you prefer hosted, Munder Difflin for a team on your computer, or Gemini tasks if you live in Google. -**Solves:** the US only limit and the data worry. -**The catch:** you run it, so keeping it secure and updated is your job. +
Animation. On a white background, a large compass card shows three directions: Not in my country, Keep my data, Agents for work. The needle swings to each in turn, and a small card under each names the picks: OpenClaw and Hermes Agent, open source picks, Claude Cowork and Munder Difflin. Tapping a direction points the needle there.
Our picks by reason for leaving Muse, from the sources above, checked 30 Oct 2026.
-## How to choose +Setup for Munder Difflin is in [how to install and use Munder Difflin](/blog/how-to-install-and-use-munder-difflin/). -- **Want Muse, but you are outside the US?** Start with OpenClaw. -- **Want errands handled but don't trust Meta with your data?** OpenClaw or Hermes Agent, with a local model if you want nothing to leave your machine. -- **Want agents that do your work, not your shopping?** [Download Munder Difflin](https://harnessmd.com/download). It is free and open source. Our [install guide](/blog/how-to-install-and-use-munder-difflin/) walks you through it. + diff --git a/blog/src/posts/what-is-instinct-ai.md b/blog/src/posts/what-is-instinct-ai.md new file mode 100644 index 0000000000..05e499e4a9 --- /dev/null +++ b/blog/src/posts/what-is-instinct-ai.md @@ -0,0 +1,76 @@ +--- +title: "What Is Instinct AI? Access, Privacy and 6 Alternatives You Can Use Now (Oct 2026)" +seoTitle: "What Is Instinct AI? Access, Privacy and Alternatives (2026)" +description: "Instinct is a personal AI agent you text or call, still in private beta. What it does, what its privacy policy says, and six texting agents you can use today." +date: 2026-10-30 +category: concepts +categoryLabel: Concepts +type: Non-technical +primaryKeyword: "instinct ai" +secondaryKeywords: ["what is instinct ai", "instinct ai alternatives", "instinct ai invite", "instinct ai privacy", "instinct ai price", "ai agent you can text"] +tags: ["Concepts", "AI Agents", "Comparisons"] +faq: + - q: "What is Instinct AI?" + a: "Instinct is a personal AI assistant you text or call. Its home page, read 30 Oct 2026, says it can use a phone and computer the way you do, for tasks such as ordering groceries, booking a train or sending flowers. TechCrunch reported on 24 Oct 2026 that it remains in private beta." + - q: "How do I get Instinct AI?" + a: "Not widely yet. TechCrunch wrote on 24 Oct 2026 that the company remains in private beta, and its home page offers Try Instinct and Invite a friend. Its terms say you must be 18 or older to use it." + - q: "How much does Instinct AI cost?" + a: "Instinct has not published a price. Its terms of service, read 30 Oct 2026, say you may be required to pay fees for certain features, charged in US dollars. Check its site before you rely on it." + - q: "Does Instinct AI train on my data?" + a: "Its privacy policy, read 30 Oct 2026, says it uses information from your use of the service to evaluate, fine tune and train its AI models. You can opt out at app.instinct.com/settings, though it may still train on information flagged for safety review. It says it does not use data received from Google Workspace APIs to train or improve AI models." + - q: "What are the best Instinct AI alternatives?" + a: "Poke, Munder Difflin, Folk, Martin, Comma and Maverick. Folk, Comma and Maverick have free options, and Comma is open source, per TechCrunch's list of 24 Oct 2026. Munder Difflin is a free and open source desktop app rather than a texting agent." +--- + +Instinct is a personal AI agent you reach by text or phone call, and it acts for you: it books, orders and sends things instead of only answering. It is still in private beta, so most people cannot use it yet. Below: what it does, what its privacy policy says, and six alternatives you can try. Checked 30 Oct 2026. + +If you want agents working on your own tasks now, [Munder Difflin](https://harnessmd.com/download) is free and open source: a desktop app that runs a team of AI agents for all kinds of knowledge work, coding included, on your own computer. This page sits in our [Concepts hub](/blog/topics/concepts/). + +
Animation. On a white background, three text message bubbles appear one at a time in a plain chat thread: Book a train home, Order groceries, Send flowers. Each bubble folds into a small done card with a tick beside it. Tapping a card unfolds it back into its message.
Instinct's home page, read 30 Oct 2026, says you can text or call it, with tasks such as booking a train home, ordering groceries and sending flowers.
+ +## What is Instinct AI? + +Instinct is a personal assistant from a San Francisco startup. Its [home page](https://instinct.com/), read 30 Oct 2026, says "there are no new interfaces. You can text or call it. It can use a phone and computer in the same way that you do." Its examples are ordering ingredients for a recipe, booking a train home, ordering groceries, sending flowers and finding a court for the weekend. + +[TechCrunch](https://techcrunch.com/2026/10/24/all-the-ai-agents-that-can-live-in-your-text-messages/) reported on 24 Oct 2026 that Instinct raised $1 billion in September 2026 at a $10 billion valuation, and that since September it gives each assistant its own email address, so it can sign up for services and contact businesses without filling your inbox. + +[VKTR](https://www.vktr.com/ai-platforms/instinct-raises-1b-at-10b-valuation-to-scale-its-personal-ai-agent/) listed other features on 28 Sep 2026: Instinct Concierge for tasks such as phone calls to restaurants, a Trusted Person Network that lets two users' agents coordinate plans and share files, and location sharing through iMessage. + +## Can you use Instinct AI today? + +Not for most people yet. TechCrunch wrote on 24 Oct 2026 that "the company remains in private beta", and the home page offers Try Instinct and Invite a friend. Its [terms of service](https://instinct.com/terms), read 30 Oct 2026, say you must be 18 or older. + +There is no public price. The terms say you "may be required to pay us fees to access or use certain features", charged in US dollars. + +
Animation. On a white background, a clipboard titled Private beta shows a guest list. Two rows read Invited and get a tick; a third row reads Waiting and keeps an empty box. A small note beside it reads 18 or older. Tapping the clipboard flips it to a second page that reads Price not published.
Private beta per TechCrunch on 24 Oct 2026; age and fees from Instinct's terms, read 30 Oct 2026.
+ +## What does Instinct do with your data? + +Its [privacy policy](https://instinct.com/privacy), read 30 Oct 2026, says it uses information collected through your use of the service "to evaluate, fine-tune, and train the AI models that power our products". You can opt out at app.instinct.com/settings, though the policy says it may still train on information flagged for safety review. It also says it does not use data received from Google Workspace APIs, such as Gmail or Google Calendar, to train or improve AI models. + +Depending on what you allow, the agent may see sensitive data, the policy says, such as payment details you give it to book rides, and your precise location if you share it. It also warns that an agent acting for you can make "unintended payments or communications to outside parties". + +
Animation. On a white background, a small mixing desk has two sliders. The first, labelled Your messages and use, slides up to a lamp marked Used to train models. The second, labelled Google Workspace data, stays down at a lamp marked Not used to train. Tapping a slider shows the line of the privacy policy behind it.
Instinct's privacy policy, read 30 Oct 2026: use of the service can train its models; Google Workspace data cannot.
+ +## What are the best Instinct AI alternatives? + +Six you can use without waiting for Instinct. Prices and details are from TechCrunch's list of 24 Oct 2026, unless stated. + +1. **Poke.** A general assistant you text, launched in March 2026, for calendars, planning, health and fitness, smart home controls and photos. In June 2026 Apple approved it as the first AI agent on Apple Messages for Business. +2. **Munder Difflin.** Not a texting agent: a free and open source desktop app that runs a team of agents for research, writing, ops and coding on engines such as Claude Code, Codex and Gemini CLI. It takes work in from Slack and webhooks and connects tools through MCP servers, skills and plugins. A mobile app is coming soon. [How to install and use Munder Difflin](/blog/how-to-install-and-use-munder-difflin/) covers setup. +3. **Folk.** Reached through iMessage, WhatsApp and Telegram, it runs on its own private cloud computer and can run code. Free, with Pro at $8.33 a month for unlimited background tasks, per TechCrunch on 24 Oct 2026. +4. **Martin.** Reachable by SMS, phone, WhatsApp, email, Slack and an iOS app, for calendars, email, reminders and calls made for you. From $21 a month, per TechCrunch on 24 Oct 2026. +5. **Comma.** Works across your browser, computer and files and answers on Signal, Telegram and WeChat. Free to start and open source. +6. **Maverick.** Lives in your texts and asks your permission before it acts. Free in beta on iMessage, with Pro at €27 a month (about $30.25), per TechCrunch on 24 Oct 2026. + +For agents built into big platforms, see [Meta Muse alternatives](/blog/meta-muse-alternatives/), [Grok Bot alternatives](/blog/grok-bot-alternatives/) and [what is ChatGPT dots](/blog/what-is-chatgpt-dots/). + +
Animation. On a white background, six small mailboxes stand in a row, labelled Poke, Munder Difflin, Folk, Martin, Comma and Maverick. Each flag rises in turn, and a tag under each shows how you reach it: Text, Desktop and Slack, iMessage, SMS and phone, Signal and Telegram, iMessage. Tapping a mailbox shows its price note.
Alternatives and prices from TechCrunch's list of 24 Oct 2026; Munder Difflin from its own site.
+ +## Should you wait for Instinct? + +Wait if you want an agent that lives in your texts and you can get access. Read the privacy policy first, because the agent can see payment details and messages you give it. + +Pick an alternative if you need one this week, want a published price, or want open source code you can read, as with Comma or Munder Difflin. + + diff --git a/docs/blog/agent-tools-today-2026-10-03/index.html b/docs/blog/agent-tools-today-2026-10-03/index.html index b681eaae6c..8e152c28a3 100644 --- a/docs/blog/agent-tools-today-2026-10-03/index.html +++ b/docs/blog/agent-tools-today-2026-10-03/index.html @@ -249,50 +249,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
diff --git a/docs/blog/agent-tools-today-2026-10-04/index.html b/docs/blog/agent-tools-today-2026-10-04/index.html index b762de707d..115051d07f 100644 --- a/docs/blog/agent-tools-today-2026-10-04/index.html +++ b/docs/blog/agent-tools-today-2026-10-04/index.html @@ -248,50 +248,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
diff --git a/docs/blog/agent-tools-today-2026-10-05/index.html b/docs/blog/agent-tools-today-2026-10-05/index.html index 169736d437..1f71680bae 100644 --- a/docs/blog/agent-tools-today-2026-10-05/index.html +++ b/docs/blog/agent-tools-today-2026-10-05/index.html @@ -246,50 +246,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
diff --git a/docs/blog/agent-tools-today-2026-10-06/index.html b/docs/blog/agent-tools-today-2026-10-06/index.html index d26b5a44d0..9e763c93fd 100644 --- a/docs/blog/agent-tools-today-2026-10-06/index.html +++ b/docs/blog/agent-tools-today-2026-10-06/index.html @@ -247,50 +247,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
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 c29d053af7..03fe6ff7e9 100644 --- a/docs/blog/agent-tools-today-2026-10-07/index.html +++ b/docs/blog/agent-tools-today-2026-10-07/index.html @@ -247,50 +247,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
diff --git a/docs/blog/agent-tools-today-2026-10-08/index.html b/docs/blog/agent-tools-today-2026-10-08/index.html index 347a4a6ba5..9ea144824d 100644 --- a/docs/blog/agent-tools-today-2026-10-08/index.html +++ b/docs/blog/agent-tools-today-2026-10-08/index.html @@ -246,50 +246,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
diff --git a/docs/blog/agent-tools-today-2026-10-09/index.html b/docs/blog/agent-tools-today-2026-10-09/index.html index fedb7651b3..6ba8397a67 100644 --- a/docs/blog/agent-tools-today-2026-10-09/index.html +++ b/docs/blog/agent-tools-today-2026-10-09/index.html @@ -247,50 +247,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
diff --git a/docs/blog/agent-tools-today-2026-10-10/index.html b/docs/blog/agent-tools-today-2026-10-10/index.html index a5c4c53ea7..6885b00513 100644 --- a/docs/blog/agent-tools-today-2026-10-10/index.html +++ b/docs/blog/agent-tools-today-2026-10-10/index.html @@ -247,50 +247,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
diff --git a/docs/blog/agent-tools-today-2026-10-11/index.html b/docs/blog/agent-tools-today-2026-10-11/index.html index 1e7c3b9321..d8af06b8be 100644 --- a/docs/blog/agent-tools-today-2026-10-11/index.html +++ b/docs/blog/agent-tools-today-2026-10-11/index.html @@ -245,50 +245,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
diff --git a/docs/blog/agent-tools-today-2026-10-12/index.html b/docs/blog/agent-tools-today-2026-10-12/index.html index 633da03a18..8e0b9f7273 100644 --- a/docs/blog/agent-tools-today-2026-10-12/index.html +++ b/docs/blog/agent-tools-today-2026-10-12/index.html @@ -243,50 +243,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
diff --git a/docs/blog/agent-tools-today-2026-10-13/index.html b/docs/blog/agent-tools-today-2026-10-13/index.html index 619a76d622..e949ca9c03 100644 --- a/docs/blog/agent-tools-today-2026-10-13/index.html +++ b/docs/blog/agent-tools-today-2026-10-13/index.html @@ -243,50 +243,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
diff --git a/docs/blog/agent-tools-today-2026-10-15/index.html b/docs/blog/agent-tools-today-2026-10-15/index.html index 12fc7c7cb4..3e253fa95b 100644 --- a/docs/blog/agent-tools-today-2026-10-15/index.html +++ b/docs/blog/agent-tools-today-2026-10-15/index.html @@ -242,50 +242,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
diff --git a/docs/blog/agent-tools-today-2026-10-16/index.html b/docs/blog/agent-tools-today-2026-10-16/index.html index 88dc97faaa..41da38e4e6 100644 --- a/docs/blog/agent-tools-today-2026-10-16/index.html +++ b/docs/blog/agent-tools-today-2026-10-16/index.html @@ -241,50 +241,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
diff --git a/docs/blog/agent-tools-today-2026-10-17/index.html b/docs/blog/agent-tools-today-2026-10-17/index.html index c581d1b0a2..49962a3d66 100644 --- a/docs/blog/agent-tools-today-2026-10-17/index.html +++ b/docs/blog/agent-tools-today-2026-10-17/index.html @@ -240,50 +240,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
diff --git a/docs/blog/agent-tools-today-2026-10-18/index.html b/docs/blog/agent-tools-today-2026-10-18/index.html index 6e93748107..aea30c8907 100644 --- a/docs/blog/agent-tools-today-2026-10-18/index.html +++ b/docs/blog/agent-tools-today-2026-10-18/index.html @@ -240,50 +240,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
diff --git a/docs/blog/agent-tools-today-2026-10-19/index.html b/docs/blog/agent-tools-today-2026-10-19/index.html index 263c879411..c58d673c94 100644 --- a/docs/blog/agent-tools-today-2026-10-19/index.html +++ b/docs/blog/agent-tools-today-2026-10-19/index.html @@ -240,50 +240,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
diff --git a/docs/blog/agent-tools-today-2026-10-21/index.html b/docs/blog/agent-tools-today-2026-10-21/index.html index 6d681b9558..a7e4b6a1b0 100644 --- a/docs/blog/agent-tools-today-2026-10-21/index.html +++ b/docs/blog/agent-tools-today-2026-10-21/index.html @@ -240,50 +240,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
diff --git a/docs/blog/agent-tools-today-2026-10-22/index.html b/docs/blog/agent-tools-today-2026-10-22/index.html index 99e8ecfde5..155de4e05e 100644 --- a/docs/blog/agent-tools-today-2026-10-22/index.html +++ b/docs/blog/agent-tools-today-2026-10-22/index.html @@ -240,50 +240,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
diff --git a/docs/blog/agent-tools-today-2026-10-23/index.html b/docs/blog/agent-tools-today-2026-10-23/index.html index 756c587b69..696e40f0cb 100644 --- a/docs/blog/agent-tools-today-2026-10-23/index.html +++ b/docs/blog/agent-tools-today-2026-10-23/index.html @@ -241,50 +241,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Black October: What PHP2Shell Is and How to Patch (Oct 2026)

-

Black October is the scramble around PHP2Shell, two critical PHP flaws fixed on 21 Oct 2026. Who found them, the fixed versions and how to patch.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 22 Oct 2026: Claude API 2026-10-21, LayerFS 1.0, PHP2Shell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 22 Oct 2026, each with its source.

+

Black October: What PHP2Shell Is and How to Patch (Oct 2026)

+

Black October is the scramble around PHP2Shell, two critical PHP flaws fixed on 21 Oct 2026. Who found them, the fixed versions and how to patch.

News - Read → + Read →
diff --git a/docs/blog/agent-tools-today-2026-10-26/index.html b/docs/blog/agent-tools-today-2026-10-26/index.html index 9c9050095d..ddc42a4214 100644 --- a/docs/blog/agent-tools-today-2026-10-26/index.html +++ b/docs/blog/agent-tools-today-2026-10-26/index.html @@ -241,50 +241,50 @@

How this list is built
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 22 Oct 2026: Claude API 2026-10-21, LayerFS 1.0, PHP2Shell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 22 Oct 2026, each with its source.

+

Black October: What PHP2Shell Is and How to Patch (Oct 2026)

+

Black October is the scramble around PHP2Shell, two critical PHP flaws fixed on 21 Oct 2026. Who found them, the fixed versions and how to patch.

News - Read → + Read →
diff --git a/docs/blog/agent-tools-today-2026-10-30/index.html b/docs/blog/agent-tools-today-2026-10-30/index.html new file mode 100644 index 0000000000..525b9d81df --- /dev/null +++ b/docs/blog/agent-tools-today-2026-10-30/index.html @@ -0,0 +1,349 @@ + + + + + + + + +Agent Tools Today (30 Oct 2026): Launches, Skills, MCP Servers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

+ +
+ +
Hand drawn sketch: a front page with five numbered lines, a clock, and a yellow character reading it out
+ +
+
+

Agent tools today, 30 Oct 2026, in one line: Mistral released the weights of Mistral Large 4, Claude Code 2.1.314 can refuse every write outside your working folders, and Herdr shipped a desktop app for terminals and coding agents. It covers 29 to 30 Oct, checked 30 Oct. An earlier edition is 26 Oct.

+

Munder Difflin is free and open source: a desktop app that runs a team of AI agents for all kinds of knowledge work, coding included, on your own computer. It is not ranked in the lists below.

+
Animation. On a white background, three envelopes drop one at a time into the slots of a mail sorting rack. The first reads Mistral Large 4 with a tag Weights out, the second Claude Code 2.1.314 with a tag Write guard, and the third Herdr with a tag Desktop app. Tapping an envelope slides it out of its slot or back in.
The day's three lead items, from Mistral's release post, Claude Code's release notes and Herdr's README, read 30 Oct 2026.
+

Top 3 launches

+
    +
  1. Mistral Large 4 weights. On 29 Oct Mistral put the weights on Hugging Face under the Mistral Ecosystem Open-Weight license, which its post calls “a modified MIT license”. The post prices the API at $0.70 per million input tokens and $2.10 per million output tokens on 29 Oct 2026. More than 1,250 points on Hacker News on 30 Oct. Details in Mistral Large 4. Source
  2. +
  3. Qwenputer. A stock Qwen 3.5 4B model with a RISC-V CPU compiled into its weights, using the model’s Gated DeltaNet layers as memory. Its write up says it runs arithmetic, C and MicroPython inside the forward pass “without any external runtime or tool usage”, and calls it “a pretty fun experimental model”. More than 680 points on Hacker News on 30 Oct. Source
  4. +
  5. Herdr desktop app. Herdr now has “a desktop app for terminals and coding agents”: spaces for work, a status for each agent (working, blocked, done or idle), and terminals that keep running when you close the window. Builds for Linux, Apple Silicon Macs and Windows, Apache 2.0, more than 210 stars on 30 Oct. See Herdr alternatives. Source
  6. +
+

Top 3 skills, MCP servers and plugins

+
    +
  1. AI Design Skills. A collection of design skills for Claude Code, Cursor, Codex, Windsurf “and anything else that reads a markdown rules file”. The first, landing-page-design, builds a landing page from intake questions to a full visual system. MIT, more than 12,000 stars, and 1,187 stars in a day on GitHub trending on 30 Oct. Source
  2. +
  3. MiniMax mcode-stack. “The workflows and skills the MiniMax Code team uses to build MiniMax Code”, each a SKILL.md skill or checklist, among them a check for whether work should go to a subagent and an audit of what tools cost in context. MIT, created 28 Oct, more than 420 stars on 30 Oct. Source
  4. +
  5. Grim Prompter. A threat modeling skill: point Claude Code, Codex or another coding agent at a repo and get a threat model traced to the code, from 36 architecture workflows and 29 method and analysis prompts. MIT, created 28 Oct, more than 160 stars on 30 Oct. Source
  6. +
+

Top 3 moves from multi agent tools

+
    +
  1. Claude Code 2.1.314. Published 30 Oct. A new permissions.blockWritesOutsideWorkingDirectories setting makes Write, Edit and NotebookEdit refuse paths outside the working folders in every permission mode. VS Code and the Claude Desktop Code tab now summarize a 200K+ token conversation left idle, and sessions no longer fail turn after turn when an admin caps a model’s effort. See Claude Code alternatives. Source
  2. +
  3. Codex 0.166.0. Published 29 Oct. It adds keyboard driven transcript selection with search, GPT-6.1 Terra in the bundled, Vertex AI and Amazon Bedrock model catalogs, codex queue --resume, and codex doctor --network-only for connection checks. Source
  4. +
  5. OpenCode 2.2.2. Published 29 Oct. Agents can now generate images by default when a connected provider has an image model, and clicking the current Git branch on the new session screen opens the worktree picker. See OpenCode alternatives. Source
  6. +
+

Top 3 rising repos

+
    +
  1. OpenMausBot. It calls itself “The open-source Grok Bot alternative: your own team of AI bots, in a chat app”, where each bot is Claude or Codex running locally with its own model and connected apps. Apache 2.0, more than 7,500 stars, and 1,199 stars in a day on GitHub trending on 30 Oct. See Grok Bot alternatives. Source
  2. +
  3. ThinkRail. A JetBrains incubator IDE built around the pi coding agent, with work isolated in git worktrees, specs kept beside the code, and Agent Skills from other coding agents read in. Apache 2.0, more than 6,000 stars, and 1,117 stars in a day on GitHub trending on 30 Oct. Source
  4. +
  5. BLA. “Blind LLM Agents”, a defensive tool that hardens software you ship so an AI reverse engineering agent hits resource budgets and follows decoys, while users see the same behavior. MIT, created 25 Oct, more than 890 stars on 30 Oct. Source
  6. +
+

Stars can rise for reasons other than use: names to watch, not picks.

+

Top 3 things people are arguing about

+
    +
  1. Can readers tell when an LLM wrote a post? In “LLM Voice” on 29 Oct, Martin Fowler writes that he urges authors “to be extra-wary of LLM-Voice” and not to have a model write a draft, since even after a human edits it, LLM Voice is very hard to remove. His site asks anyone who uses AI to help write to say how. More than 370 points on Hacker News on 30 Oct. Source
  2. +
  3. Where do the numbers AI assistants quote come from? Trakkr traced 1,285 statistics cited by five AI assistants, published 28 Oct. 40% reached a study that says the same thing, 8% reached the study with the number changed, 40% stopped at a source it could not check, and 11% led nowhere. More than 150 points on Hacker News on 30 Oct. Source
  4. +
  5. What are agents doing to GitHub? The New Stack reported on 28 Oct that GitHub now sees 7.4 billion commits a month, up from 2.9 billion in August, and has added 4 million CPU cores this year. GitHub puts the growth down mostly to “agentic demand”. More than 45 points on Hacker News on 30 Oct. Source
  6. +
+

How this list is built

+

For this edition, covering 29 to 30 Oct, we read the GitHub releases of 16 tracked tools, vendor blogs and changelogs, GitHub trending, and the Hacker News front page. We did not read X or Reddit for it. A name only makes a list with a link that was opened and a signal that can be shown: points, stars or a dated release. Repos are checked against the GitHub API before they appear. New here? Start with the install guide.

+ + + + + + +
+ + +
+ + + + +
+ + +
+ +
+ + + + + + diff --git a/docs/blog/agents-rule-of-two/index.html b/docs/blog/agents-rule-of-two/index.html index e3a7731936..217ff51998 100644 --- a/docs/blog/agents-rule-of-two/index.html +++ b/docs/blog/agents-rule-of-two/index.html @@ -331,6 +331,22 @@

FAQ

Related in Concepts

+ -
diff --git a/docs/blog/ai-agent-glossary/index.html b/docs/blog/ai-agent-glossary/index.html index 3aa88090f0..c07af2eb0e 100644 --- a/docs/blog/ai-agent-glossary/index.html +++ b/docs/blog/ai-agent-glossary/index.html @@ -303,6 +303,22 @@

FAQ

Related in Concepts

+ -
diff --git a/docs/blog/assets/media/agent-tools-today-2026-10-30/motion.css b/docs/blog/assets/media/agent-tools-today-2026-10-30/motion.css new file mode 100644 index 0000000000..2c898d64a9 --- /dev/null +++ b/docs/blog/assets/media/agent-tools-today-2026-10-30/motion.css @@ -0,0 +1,13 @@ +/* Bright coded scene for "Agent tools today, 30 Oct 2026". 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/docs/blog/assets/media/agent-tools-today-2026-10-30/motion.js b/docs/blog/assets/media/agent-tools-today-2026-10-30/motion.js new file mode 100644 index 0000000000..99ba30c86c --- /dev/null +++ b/docs/blog/assets/media/agent-tools-today-2026-10-30/motion.js @@ -0,0 +1,115 @@ +/* Bright coded scene for "Agent tools today, 30 Oct 2026". 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 SC = {}; + + /* ---- three envelopes drop into a mail sorting rack ---- */ + SC.sorter = { + dur: 8.5, still: 7, + build(svg, api) { + const X0 = 48, DW = 16, S = (704 - 4 * DW) / 3, EW = 196, EH = 250, TOP = 270, OUT = 180; + const MAIL = [ + ["Mistral", "Large 4", "Weights out", SKY], + ["Claude Code", "2.1.314", "Write guard", LIL], + ["Herdr", "", "Desktop app", MINT], + ]; + const root = el("g", { transform: "translate(0 -64)" }, svg); + const grain = (d, p) => el("path", { d, stroke: "#fff", "stroke-opacity": 0.6, "stroke-width": 2.5, fill: "none", "stroke-linecap": "round" }, p); + el("ellipse", { cx: 400, cy: 560, rx: 370, ry: 10, fill: SOFT }, root); + el("rect", { x: X0 + 8, y: 216, width: 688, height: 316, rx: 10, fill: SOFT, stroke: INK, "stroke-width": 3 }, root); + for (let i = 0; i < 4; i++) { + const x = X0 + i * (S + DW); + el("rect", { x, y: 196, width: DW, height: 336, rx: 8, fill: YEL, stroke: INK, "stroke-width": 3 }, root); + grain(`M${x + 8} 214 V300 M${x + 8} 330 V440`, root); + } + const layer = el("g", {}, root); + el("rect", { x: 40, y: 454, width: 720, height: 78, rx: 12, fill: YEL, stroke: INK, "stroke-width": 3 }, root); + grain("M72 476 C200 468 330 486 460 476 S660 468 728 478", root); + grain("M120 506 C260 498 380 514 520 506 S640 500 690 506", root); + el("ellipse", { cx: 600, cy: 492, rx: 14, ry: 5, fill: "none", stroke: "#fff", "stroke-opacity": 0.6, "stroke-width": 2.5 }, root); + el("rect", { x: 28, y: 526, width: 744, height: 20, rx: 10, fill: YEL, stroke: INK, "stroke-width": 3 }, root); + const env = MAIL.map(([a, b, tag, col], i) => { + const g = el("g", {}, layer); + el("rect", { x: -8, y: -8, width: EW + 16, height: EH + 16, rx: 16, fill: "none", stroke: INK, "stroke-width": 2.5, "stroke-dasharray": "6 6", class: "mg-ring" }, g); + el("rect", { width: EW, height: EH, rx: 10, fill: "#fff", stroke: INK, "stroke-width": 3 }, g); + el("path", { d: `M4 5 L${EW / 2} 52 L${EW - 4} 5`, stroke: MUTE, "stroke-width": 2.5, fill: "none", "stroke-linejoin": "round", "stroke-linecap": "round" }, g); + const name = { "text-anchor": "middle", "font-family": MONO, "font-size": 24, "font-weight": 700 }; + if (b) { txt(g, EW / 2, 92, a, name); txt(g, EW / 2, 120, b, name); } else txt(g, EW / 2, 106, a, name); + const chip = el("rect", { y: 138, height: 34, rx: 17, fill: col, stroke: INK, "stroke-width": 2.5 }, g); + const tt = txt(g, EW / 2, 161, tag, { "text-anchor": "middle", "font-size": 19, "font-weight": 600 }); + const w = (tt.getComputedTextLength() || 110) + 32; + chip.setAttribute("x", EW / 2 - w / 2); chip.setAttribute("width", w); + const st = { out: false, at: -99 }; + button(g, `${b ? a + " " + b : a}, ${tag}`, () => { + st.out = !st.out; st.at = api.calm ? -99 : api.now(); g.setAttribute("aria-pressed", st.out); + if (api.calm) api.redraw(); else api.poke(); + }); + g.setAttribute("aria-pressed", "false"); + return { g, st, x: X0 + DW + i * (S + DW) + (S - EW) / 2, d: 0.5 + i * 1.4, r: [-7, 6, -5][i] }; + }); + return (t, now) => { + const fade = 1 - seg(t, 7.6, 8.2); + env.forEach((e) => { + const k = seg(t, e.d, e.d + 0.75), bump = Math.sin(seg(t, e.d + 0.75, e.d + 1.05) * Math.PI); + const p = io(seg(now - e.st.at, 0, 0.55)), slide = e.st.out ? -OUT * p : -OUT * (1 - p); + const y = TOP - 620 * (1 - k * k) - 14 * bump + slide, r = e.r * (1 - k) + e.r * 0.25 * bump; + e.g.setAttribute("transform", `translate(${e.x + EW / 2} ${y + EH / 2}) rotate(${r}) translate(${-EW / 2} ${-EH / 2})`); + e.g.setAttribute("opacity", t < e.d ? 0 : fade); + }); + }; + }, + }; + + /* ---- 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 = { calm, redraw: () => frame(), 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/docs/blog/assets/media/agent-tools-today-2026-10-30/sorter.png b/docs/blog/assets/media/agent-tools-today-2026-10-30/sorter.png new file mode 100644 index 0000000000..a53b116cfa Binary files /dev/null and b/docs/blog/assets/media/agent-tools-today-2026-10-30/sorter.png differ diff --git a/docs/blog/assets/media/meta-muse-alternatives/compass.png b/docs/blog/assets/media/meta-muse-alternatives/compass.png new file mode 100644 index 0000000000..205fac8214 Binary files /dev/null and b/docs/blog/assets/media/meta-muse-alternatives/compass.png differ diff --git a/docs/blog/assets/media/meta-muse-alternatives/globe.png b/docs/blog/assets/media/meta-muse-alternatives/globe.png new file mode 100644 index 0000000000..44423325a0 Binary files /dev/null and b/docs/blog/assets/media/meta-muse-alternatives/globe.png differ diff --git a/docs/blog/assets/media/meta-muse-alternatives/hero.png b/docs/blog/assets/media/meta-muse-alternatives/hero.png new file mode 100644 index 0000000000..cee2c5e54e Binary files /dev/null and b/docs/blog/assets/media/meta-muse-alternatives/hero.png differ diff --git a/docs/blog/assets/media/meta-muse-alternatives/motion.css b/docs/blog/assets/media/meta-muse-alternatives/motion.css new file mode 100644 index 0000000000..ae11628cf1 --- /dev/null +++ b/docs/blog/assets/media/meta-muse-alternatives/motion.css @@ -0,0 +1,13 @@ +/* Bright coded scenes for "Meta Muse alternatives". 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/docs/blog/assets/media/meta-muse-alternatives/motion.js b/docs/blog/assets/media/meta-muse-alternatives/motion.js new file mode 100644 index 0000000000..35149bb66b --- /dev/null +++ b/docs/blog/assets/media/meta-muse-alternatives/motion.js @@ -0,0 +1,245 @@ +/* Bright coded scenes for "Meta Muse alternatives". 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 }); + }; + + /* ---- a compass face drawn around 0,0; returns the needle group ---- */ + const compass = (g, r) => { + el("circle", { r: r + 14, fill: SKY, stroke: INK, "stroke-width": 3 }, g); + el("circle", { r, fill: "#fff", stroke: INK, "stroke-width": 3 }, g); + for (let i = 0; i < 24; i++) { + const a = (i * 15 * Math.PI) / 180, l = i % 6 === 0 ? 16 : 8; + el("path", { d: `M${Math.sin(a) * (r - 6)} ${-Math.cos(a) * (r - 6)} L${Math.sin(a) * (r - 6 - l)} ${-Math.cos(a) * (r - 6 - l)}`, stroke: INK, "stroke-width": i % 6 === 0 ? 3 : 2, "stroke-linecap": "round" }, g); + } + const n = el("g", {}, g), L = r - 26, w = r * 0.16; + el("path", { d: `M0 ${-L} L${w} 0 L${-w} 0 Z`, fill: BLUE, stroke: INK, "stroke-width": 3, "stroke-linejoin": "round" }, n); + el("path", { d: `M0 ${L * 0.72} L${w} 0 L${-w} 0 Z`, fill: "#fff", stroke: INK, "stroke-width": 3, "stroke-linejoin": "round" }, n); + el("circle", { r: w * 0.75, fill: YEL, stroke: INK, "stroke-width": 3 }, g); + return n; + }; + + const SC = {}; + + /* ---- 1. a globe turns, then three launch pins drop ---- */ + SC.globe = { + dur: 11, still: 10.5, + build(svg, api) { + const C = [400, 290], R = 185; + const clip = el("clipPath", { id: "mg-globe-clip" }, el("defs", {}, svg)); + el("circle", { cx: C[0], cy: C[1], r: R }, clip); + el("circle", { cx: C[0], cy: C[1], r: R, fill: SKY }, svg); + const sph = el("g", { "clip-path": "url(#mg-globe-clip)" }, svg); + const land = el("g", {}, sph); + const blobs = [ + "M262 158 Q300 128 352 144 Q384 156 378 196 Q372 232 342 248 Q330 276 304 284 Q282 270 286 238 Q262 214 252 190 Q248 170 262 158 Z", + "M330 302 Q362 296 380 318 Q392 352 372 392 Q356 428 340 434 Q330 404 332 370 Q318 336 330 302 Z", + "M440 286 Q480 272 506 292 Q520 326 500 360 Q482 398 464 402 Q450 372 452 340 Q430 312 440 286 Z", + "M450 150 Q500 128 556 146 Q584 166 572 196 Q546 214 512 210 Q480 224 458 206 Q438 178 450 150 Z", + "M548 236 Q560 232 566 244 Q568 262 556 276 Q546 284 542 272 Q540 252 548 236 Z", + ]; + [-400, 0, 400].forEach((dx) => { const g = el("g", { transform: `translate(${dx} 0)` }, land); blobs.forEach((d) => el("path", { d, fill: MINT, stroke: INK, "stroke-width": 2.5, "stroke-linejoin": "round" }, g)); }); + el("ellipse", { cx: C[0], cy: C[1], rx: R, ry: 26, fill: "none", stroke: "#fff", "stroke-width": 2.5, "stroke-opacity": 0.8 }, sph); + const mer = [0, 1].map(() => el("ellipse", { cx: C[0], cy: C[1], rx: R, ry: R, fill: "none", stroke: "#fff", "stroke-width": 2.5, "stroke-opacity": 0.8 }, sph)); + el("circle", { cx: C[0], cy: C[1], r: R, fill: "none", stroke: INK, "stroke-width": 3 }, svg); + const P = [ + { name: "US", date: "8 Sep", src: "Meta launch post", col: YEL, at: [318, 252], card: [40, 252, 150, 78], d: 3.0 }, + { name: "Canada", date: "18 Sep", src: "iPhone in Canada", col: BLUE, at: [332, 186], card: [40, 132, 150, 78], d: 4.2 }, + { name: "Japan", date: "23 Oct", src: "RuntimeWire", col: LIL, at: [554, 262], card: [612, 196, 156, 116], d: 5.4, note: "Reported" }, + ]; + const pins = P.map((p, i) => { + const g = el("g", {}, svg), [x, y] = p.at, [cx, cy, cw, ch] = p.card; + const shadow = el("ellipse", { cx: x, cy: y, rx: 12, ry: 4, fill: INK, "fill-opacity": 0.25 }, g); + const ex = cx + (cx < 400 ? cw : 0), ey = cy + 36; + const lead = el("path", { d: `M${x} ${y - 30} L${ex} ${ey}`, stroke: INK, "stroke-width": 2, "stroke-dasharray": "3 6", "stroke-linecap": "round", fill: "none" }, g); + const card = el("g", {}, g); + el("rect", { x: cx - 6, y: cy - 6, width: cw + 12, height: ch + 12, rx: 20, fill: "none", stroke: INK, "stroke-width": 2, "stroke-dasharray": "4 6", class: "mg-ring" }, card); + const face = el("rect", { x: cx, y: cy, width: cw, height: ch, rx: 16, fill: "#fff", stroke: INK, "stroke-width": 3 }, card); + txt(card, cx + 18, cy + 34, p.name, { "font-size": 26, "font-weight": 700 }); + txt(card, cx + 18, cy + 62, p.date, { "font-family": MONO, "font-size": 20, "font-weight": 500 }); + if (p.note) { el("rect", { x: cx + 14, y: cy + 76, width: 110, height: 28, rx: 14, fill: SOFT, stroke: INK, "stroke-width": 1.5 }, card); txt(card, cx + 69, cy + 96, p.note, { "text-anchor": "middle", "font-size": 16, "font-weight": 600, fill: MUTE }); } + const pin = el("g", {}, g); + el("path", { d: "M0 0 C-6 -10 -16 -20 -16 -32 A16 16 0 1 1 16 -32 C16 -20 6 -10 0 0 Z", fill: p.col, stroke: INK, "stroke-width": 3, "stroke-linejoin": "round" }, pin); + el("circle", { cx: 0, cy: -32, r: 6, fill: "#fff", stroke: INK, "stroke-width": 2.5 }, pin); + button(g, `${p.name}, ${p.date}${p.note ? ", " + p.note : ""}: ${p.src}`, () => { pinned = i; api.seek(6.4); }); + return { g, pin, shadow, lead, card, face, x, y }; + }); + let pinned = -1, last = 0; + const tip = strip(svg, 528, 560); + return (t) => { + if (t < last) pinned = -1; last = t; + const spin = io(seg(t, 0, 2.8)), shift = (700 * (1 - spin)) % 400; + land.setAttribute("transform", `translate(${shift} 0)`); + mer.forEach((m, i) => { const ph = (shift / 400) * Math.PI + Math.PI / 4 + i * Math.PI / 2; m.setAttribute("rx", Math.max(2, Math.abs(Math.cos(ph)) * R)); }); + let show = -1; + pins.forEach((p, i) => { + const k = seg(t, P[i].d, P[i].d + 0.55), drop = ob(k), c = oc(seg(t, P[i].d + 0.4, P[i].d + 0.9)); + tf(p.pin, p.x, p.y - 140 * (1 - drop)); p.pin.setAttribute("opacity", k > 0 ? 1 : 0); + p.shadow.setAttribute("opacity", k); p.lead.setAttribute("opacity", c); + p.card.setAttribute("opacity", c); p.card.setAttribute("transform", `translate(0 ${12 * (1 - c)})`); + p.face.setAttribute("fill", pinned === i ? P[i].col : "#fff"); + if (t >= P[i].d) show = i; + }); + if (pinned >= 0) show = pinned; + tip.textContent = show < 0 ? "Tapping a pin shows its source" : `${P[show].name}: ${P[show].src}`; + }; + }, + }; + + /* ---- 2. one training switch, On then Off ---- */ + SC.sliders = { + dur: 9, still: 8.6, + build(svg, api) { + const panel = el("g", {}, svg); + el("rect", { x: 60, y: 60, width: 680, height: 400, rx: 28, fill: "#fff", stroke: INK, "stroke-width": 3 }, panel); + txt(panel, 104, 140, "Muse", { "font-size": 46, "font-weight": 700 }); + const crumb = txt(panel, 104, 192, "", { "font-size": 24, "font-weight": 500, fill: MUTE }); + el("path", { d: "M104 230 H696", stroke: SOFT, "stroke-width": 4, "stroke-linecap": "round" }, panel); + el("rect", { x: 92, y: 262, width: 616, height: 160, rx: 22, fill: SOFT }, panel); + txt(panel, 128, 330, "Use my interactions", { "font-size": 30, "font-weight": 600 }); + txt(panel, 128, 370, "to improve models", { "font-size": 30, "font-weight": 600 }); + const sw = el("g", {}, panel); + el("rect", { x: 546, y: 288, width: 136, height: 88, rx: 44, fill: "none", stroke: INK, "stroke-width": 2, "stroke-dasharray": "4 6", class: "mg-ring" }, sw); + const track = el("rect", { x: 556, y: 298, width: 116, height: 68, rx: 34, stroke: INK, "stroke-width": 3 }, sw); + const pulse = el("circle", { r: 28, fill: "none", stroke: SKY, "stroke-width": 4 }, sw); + const knob = el("circle", { r: 25, cy: 332, fill: "#fff", stroke: INK, "stroke-width": 3 }, sw); + const word = txt(sw, 614, 405, "", { "text-anchor": "middle", "font-size": 22, "font-weight": 700 }); + sw.setAttribute("role", "switch"); + const LINE = "Settings, Data controls"; + let user = null, last = 0; + button(sw, "Use my interactions to improve models", () => { user = !(cur > 0.5); api.seek(5.4); }); + sw.setAttribute("role", "switch"); + el("rect", { x: 100, y: 500, width: 600, height: 48, rx: 24, fill: SOFT }, svg); + txt(svg, 400, 531, "Tapping the switch turns it back on or off", { "text-anchor": "middle", "font-size": 20, "font-weight": 500 }); + let cur = 1; + return (t) => { + if (t < last) user = null; last = t; + const p = ob(seg(t, 0, 0.7)); + panel.setAttribute("transform", `translate(400 260) scale(${0.85 + 0.15 * p}) translate(-400 -260)`); panel.setAttribute("opacity", seg(t, 0, 0.3)); + crumb.textContent = LINE.slice(0, Math.round(LINE.length * seg(t, 2.4, 3.6))); + const slide = io(seg(t, 4.3, 5.0)); + cur = user == null ? 1 - slide : user ? 1 : 0; + const kx = 590 + 48 * cur; + knob.setAttribute("cx", kx); + track.setAttribute("fill", cur > 0.5 ? BLUE : "#fff"); + word.textContent = cur > 0.5 ? "On" : "Off"; + sw.setAttribute("aria-checked", cur > 0.5 ? "true" : "false"); + const q = user == null ? seg(t, 5.0, 5.8) : 0; + pulse.setAttribute("cx", kx); pulse.setAttribute("cy", 332); + pulse.setAttribute("r", 26 + 30 * oc(q)); pulse.setAttribute("stroke-opacity", q > 0 && q < 1 ? 1 - q : 0); + }; + }, + }; + + /* ---- 3. a compass needle points at three reasons to leave ---- */ + SC.compass = { + dur: 10, still: 9.6, + build(svg, api) { + const C = [400, 268]; + el("rect", { x: 24, y: 22, width: 752, height: 380, rx: 28, fill: "#fff", stroke: INK, "stroke-width": 3 }, svg); + const D = [ + { label: "Not in my country", at: [152, 112], w: 232, col: YEL, pick: ["OpenClaw and", "Hermes Agent"] }, + { label: "Keep my data", at: [400, 72], w: 184, col: MINT, pick: ["Open source picks"] }, + { label: "Agents for work", at: [648, 112], w: 212, col: LIL, pick: ["Claude Cowork", "and Munder Difflin"] }, + ]; + D.forEach((d) => { d.ang = (Math.atan2(d.at[0] - C[0], C[1] - d.at[1]) * 180) / Math.PI; }); + const g = el("g", {}, svg); tf(g, C[0], C[1]); + const needle = compass(g, 104); + const chips = D.map((d, i) => { + const b = el("g", {}, svg), [x, y] = d.at; + el("rect", { x: x - d.w / 2 - 6, y: y - 30, width: d.w + 12, height: 60, rx: 30, fill: "none", stroke: INK, "stroke-width": 2, "stroke-dasharray": "4 6", class: "mg-ring" }, b); + const face = el("rect", { x: x - d.w / 2, y: y - 24, width: d.w, height: 48, rx: 24, fill: "#fff", stroke: INK, "stroke-width": 3 }, b); + txt(b, x, y + 8, d.label, { "text-anchor": "middle", "font-size": 22, "font-weight": 700 }); + button(b, `${d.label}: ${d.pick.join(" ")}`, () => { pick = i; from = angle; pickAt = api.now(); api.seek(6.6); }); + const card = el("g", {}, svg), cx = x; + el("rect", { x: cx - 115, y: 424, width: 230, height: 96, rx: 18, fill: "#fff", stroke: INK, "stroke-width": 3 }, card); + el("circle", { cx: cx - 96, cy: 444, r: 7, fill: d.col, stroke: INK, "stroke-width": 2 }, card); + d.pick.forEach((s, j) => txt(card, cx, (d.pick.length === 1 ? 480 : 466) + j * 30, s, { "text-anchor": "middle", "font-family": MONO, "font-size": 18, "font-weight": 700 })); + return { face, card }; + }); + el("rect", { x: 140, y: 540, width: 520, height: 44, rx: 22, fill: SOFT }, svg); + txt(svg, 400, 569, "Tapping a direction points the needle there", { "text-anchor": "middle", "font-size": 19, "font-weight": 500 }); + let pick = -1, from = 0, pickAt = 0, angle = 0, last = 0; + const swings = [[0, 1.6, -330, D[0].ang], [3.0, 3.9, D[0].ang, D[1].ang], [5.2, 6.1, D[1].ang, D[2].ang]]; + return (t, now) => { + if (t < last) pick = -1; last = t; + if (pick >= 0) angle = from + (D[pick].ang - from) * ob(seg(now - pickAt, 0, 0.7)); + else { angle = swings[0][2]; swings.forEach(([a, b, f, to]) => { if (t >= a) angle = f + (to - f) * ob(seg(t, a, b)); }); } + needle.setAttribute("transform", `rotate(${angle})`); + const at = pick >= 0 ? pick : t >= swings[2][0] + 0.5 ? 2 : t >= swings[1][0] + 0.5 ? 1 : t >= 1.2 ? 0 : -1; + chips.forEach((c, i) => { + c.face.setAttribute("fill", i === at ? D[i].col : "#fff"); + const k = oc(seg(t, [1.4, 3.8, 6.0][i], [1.9, 4.3, 6.5][i])); + c.card.setAttribute("opacity", pick >= 0 ? 1 : k); c.card.setAttribute("transform", `translate(0 ${pick >= 0 ? 0 : 16 * (1 - k)})`); + }); + }; + }, + }; + + /* ---- title card, 16 by 9 ---- */ + SC.hero = { + w: 960, h: 540, dur: 1, still: 0, + build(svg) { + el("rect", { x: 64, y: 62, width: 176, height: 44, rx: 22, fill: LIL, stroke: INK, "stroke-width": 2.5 }, svg); + txt(svg, 152, 91, "Comparisons", { "text-anchor": "middle", "font-size": 20, "font-weight": 700 }); + txt(svg, 64, 210, "Meta Muse", { "font-size": 84, "font-weight": 700 }); + txt(svg, 64, 300, "alternatives", { "font-size": 84, "font-weight": 700 }); + el("path", { d: "M66 328 H520", stroke: YEL, "stroke-width": 14, "stroke-linecap": "round" }, svg); + txt(svg, 64, 388, "7 picks, open source and hosted", { "font-size": 30, "font-weight": 500, fill: MUTE }); + txt(svg, 64, 478, "Checked 30 Oct 2026", { "font-family": MONO, "font-size": 18, "font-weight": 500, fill: MUTE }); + const g = el("g", {}, svg); tf(g, 770, 290); + compass(g, 112).setAttribute("transform", "rotate(38)"); + return () => {}; + }, + }; + + /* ---- 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/docs/blog/assets/media/meta-muse-alternatives/sliders.png b/docs/blog/assets/media/meta-muse-alternatives/sliders.png new file mode 100644 index 0000000000..3e14c27835 Binary files /dev/null and b/docs/blog/assets/media/meta-muse-alternatives/sliders.png differ diff --git a/docs/blog/assets/media/what-is-instinct-ai/bubbles.png b/docs/blog/assets/media/what-is-instinct-ai/bubbles.png new file mode 100644 index 0000000000..4627c6b83d Binary files /dev/null and b/docs/blog/assets/media/what-is-instinct-ai/bubbles.png differ diff --git a/docs/blog/assets/media/what-is-instinct-ai/guestlist.png b/docs/blog/assets/media/what-is-instinct-ai/guestlist.png new file mode 100644 index 0000000000..241f98bd61 Binary files /dev/null and b/docs/blog/assets/media/what-is-instinct-ai/guestlist.png differ diff --git a/docs/blog/assets/media/what-is-instinct-ai/hero.png b/docs/blog/assets/media/what-is-instinct-ai/hero.png new file mode 100644 index 0000000000..3611feafeb Binary files /dev/null and b/docs/blog/assets/media/what-is-instinct-ai/hero.png differ diff --git a/docs/blog/assets/media/what-is-instinct-ai/mailboxes.png b/docs/blog/assets/media/what-is-instinct-ai/mailboxes.png new file mode 100644 index 0000000000..11a35ec7ab Binary files /dev/null and b/docs/blog/assets/media/what-is-instinct-ai/mailboxes.png differ diff --git a/docs/blog/assets/media/what-is-instinct-ai/mixer.png b/docs/blog/assets/media/what-is-instinct-ai/mixer.png new file mode 100644 index 0000000000..d64dcde6b5 Binary files /dev/null and b/docs/blog/assets/media/what-is-instinct-ai/mixer.png differ diff --git a/docs/blog/assets/media/what-is-instinct-ai/motion.css b/docs/blog/assets/media/what-is-instinct-ai/motion.css new file mode 100644 index 0000000000..121f8af384 --- /dev/null +++ b/docs/blog/assets/media/what-is-instinct-ai/motion.css @@ -0,0 +1,13 @@ +/* Bright coded scenes for "What is Instinct AI?". 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/docs/blog/assets/media/what-is-instinct-ai/motion.js b/docs/blog/assets/media/what-is-instinct-ai/motion.js new file mode 100644 index 0000000000..5cb701ae88 --- /dev/null +++ b/docs/blog/assets/media/what-is-instinct-ai/motion.js @@ -0,0 +1,299 @@ +/* Bright coded scenes for "What is Instinct AI?". 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 RM = matchMedia("(prefers-reduced-motion: reduce)").matches; + 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 ring = (g, x, y, w, h, rx) => el("rect", { x, y, width: w, height: h, rx, fill: "none", stroke: INK, "stroke-width": 2, "stroke-dasharray": "4 6", class: "mg-ring" }, g); + const measure = (svg, s, a) => { const n = txt(svg, 0, -99, s, a), w = n.getComputedTextLength(); n.remove(); return w; }; + /* a toggle that eases over half a second, or snaps under reduced motion */ + const flip = (s, now) => { const p = RM ? 1 : seg(now - s.at, 0, 0.5); return s.on ? p : 1 - p; }; + const squashY = (n, cy, sy) => n.setAttribute("transform", `translate(0 ${cy}) scale(1 ${Math.max(sy, 0.001)}) translate(0 ${-cy})`); + const squashX = (n, cx, sx) => n.setAttribute("transform", `translate(${cx} 0) scale(${Math.max(sx, 0.001)} 1) translate(${-cx} 0)`); + const tickPath = (p, x, y, s = 1) => el("path", { d: `M${x - 7 * s} ${y} l${5 * s} ${5 * s} l${10 * s} ${-11 * s}`, stroke: INK, "stroke-width": 3, fill: "none", "stroke-linecap": "round", "stroke-linejoin": "round" }, p); + + const SC = {}; + + /* ---- 1. three messages fold into done cards ---- */ + SC.bubbles = { + dur: 8, still: 7, + build(svg, api) { + const root = el("g", {}, svg); + el("rect", { x: 240, y: 28, width: 320, height: 544, rx: 46, fill: "#fff", stroke: INK, "stroke-width": 3 }, root); + el("rect", { x: 360, y: 48, width: 80, height: 12, rx: 6, fill: SOFT, stroke: INK, "stroke-width": 2 }, root); + el("rect", { x: 264, y: 496, width: 272, height: 44, rx: 22, fill: SOFT, stroke: INK, "stroke-width": 2 }, root); + const R = 528, MSG = ["Book a train home", "Order groceries", "Send flowers"]; + let touched = false; + const msgs = MSG.map((s, i) => { + const cy = 170 + i * 110, g = el("g", {}, root); + const bw = measure(svg, s, { "font-size": 22 }) + 44, bx = R - bw, by = cy - 30; + const bub = el("g", {}, g); + el("path", { d: `M${bx + 24} ${by} H${R - 24} Q${R} ${by} ${R} ${by + 24} V${by + 54} Q${R} ${by + 60} ${R - 6} ${by + 60} H${bx + 24} Q${bx} ${by + 60} ${bx} ${by + 36} V${by + 24} Q${bx} ${by} ${bx + 24} ${by} Z`, fill: BLUE, stroke: INK, "stroke-width": 3 }, bub); + txt(bub, R - 22, cy + 8, s, { "font-size": 22, "text-anchor": "end" }); + const cw = measure(svg, s, { "font-size": 19 }) + 76, cx = R - cw; + const card = el("g", {}, g); + el("rect", { x: cx, y: cy - 24, width: cw, height: 48, rx: 14, fill: "#fff", stroke: INK, "stroke-width": 2.5 }, card); + el("circle", { cx: cx + 26, cy, r: 14, fill: MINT, stroke: INK, "stroke-width": 2 }, card); + tickPath(card, cx + 26, cy + 1, 0.8); + txt(card, cx + 50, cy + 7, s, { "font-size": 19 }); + ring(g, bx - 8, by - 8, bw + 16, 76, 28); + const st = { on: false, at: -99 }; + button(g, s, () => { touched = true; st.on = !st.on; st.at = api.now(); api.poke(); }); + return { g, bub, card, cy, st }; + }); + return (t, now) => { + const T = touched ? 7 : t; + root.setAttribute("opacity", 1 - seg(T, 7.6, 8)); + msgs.forEach((m, i) => { + const a = 0.4 + i, f = 3.4 + i * 0.6, app = ob(seg(T, a, a + 0.45)); + const k = touched ? 1 - flip(m.st, now) : io(seg(T, f, f + 0.6)); + m.g.setAttribute("opacity", seg(T, a, a + 0.15)); + m.g.setAttribute("transform", `translate(0 ${24 * (1 - app)})`); + squashY(m.bub, m.cy, k < 0.5 ? 1 - 2 * k : 0); + squashY(m.card, m.cy, k < 0.5 ? 0 : 2 * k - 1); + }); + }; + }, + }; + + /* ---- 2. a private beta guest list on a clipboard ---- */ + SC.guestlist = { + dur: 7, still: 6, + build(svg, api) { + const root = el("g", {}, svg); + const C = 290, board = el("g", {}, root); + el("rect", { x: 130, y: 64, width: 320, height: 490, rx: 26, fill: BLUE, stroke: INK, "stroke-width": 3 }, board); + const paper = el("g", {}, board); + el("rect", { x: 154, y: 112, width: 272, height: 418, rx: 12, fill: "#fff", stroke: INK, "stroke-width": 2.5 }, paper); + const p1 = el("g", {}, paper), p2 = el("g", {}, paper); + const title = el("g", {}, p1); + txt(title, C, 180, "Private beta", { "text-anchor": "middle", "font-size": 34, "font-weight": 700 }); + el("path", { d: `M${C - 96} 200 H${C + 96}`, stroke: YEL, "stroke-width": 8, "stroke-linecap": "round" }, title); + const rows = [["Invited", true], ["Invited", true], ["Waiting", false]].map(([s, ok], i) => { + const y = 270 + i * 80, g = el("g", {}, p1); + const box = el("rect", { x: 186, y: y - 22, width: 40, height: 40, rx: 8, fill: "#fff", stroke: INK, "stroke-width": 3 }, g); + const tk = ok ? tickPath(g, 206, y, 1.2) : null; + txt(g, 246, y + 10, s, { "font-size": 30 }); + el("path", { d: `M186 ${y + 36} H394`, stroke: SOFT, "stroke-width": 3, "stroke-linecap": "round" }, g); + return { g, box, tk, ok }; + }); + txt(p2, C, 300, "Price not", { "text-anchor": "middle", "font-size": 40, "font-weight": 700 }); + txt(p2, C, 352, "published", { "text-anchor": "middle", "font-size": 40, "font-weight": 700 }); + el("path", { d: `M${C - 90} 380 H${C + 90}`, stroke: LIL, "stroke-width": 8, "stroke-linecap": "round" }, p2); + el("rect", { x: 230, y: 40, width: 120, height: 50, rx: 14, fill: LIL, stroke: INK, "stroke-width": 3 }, board); + el("rect", { x: 266, y: 54, width: 48, height: 14, rx: 7, fill: "#fff", stroke: INK, "stroke-width": 2 }, board); + ring(board, 118, 28, 344, 538, 32); + const note = el("g", {}, root); + el("rect", { x: 0, y: 0, width: 190, height: 110, rx: 10, fill: SKY, stroke: INK, "stroke-width": 3 }, note); + el("rect", { x: 65, y: -12, width: 60, height: 22, rx: 4, fill: SOFT, stroke: INK, "stroke-width": 2 }, note); + txt(note, 95, 66, "18 or older", { "text-anchor": "middle", "font-size": 28, "font-weight": 700 }); + const st = { on: false, at: -99 }; + let touched = false; + button(board, "Private beta guest list", () => { touched = true; st.on = !st.on; st.at = api.now(); api.poke(); }); + return (t, now) => { + const T = touched ? 6 : t; + root.setAttribute("opacity", 1 - seg(T, 6.6, 7)); + const d = ob(seg(T, 0.1, 0.9)); + board.setAttribute("transform", `translate(0 ${-60 * (1 - d)})`); board.setAttribute("opacity", seg(T, 0.1, 0.3)); + p1.setAttribute("opacity", 1); + title.setAttribute("opacity", seg(T, 0.9, 1.3)); + rows.forEach((r, i) => { + const a = 1.3 + i * 0.5, k = oc(seg(T, a, a + 0.4)); + r.g.setAttribute("opacity", k); r.g.setAttribute("transform", `translate(${30 * (1 - k)} 0)`); + if (r.ok) { const p = ob(seg(T, a + 0.4, a + 0.75)); r.box.setAttribute("fill", p > 0.05 ? MINT : "#fff"); r.tk.setAttribute("opacity", p > 0.05 ? 1 : 0); r.tk.setAttribute("transform", `translate(206 ${270 + i * 80}) scale(${cl(p, 0, 1.3)}) translate(-206 ${-(270 + i * 80)})`); } + else { const w = seg(T, 3.0, 3.6); r.box.setAttribute("transform", `rotate(${Math.sin(w * Math.PI * 4) * 8 * (1 - w)} 206 ${270 + i * 80})`); } + }); + const n = oc(seg(T, 3.4, 4.1)); + note.setAttribute("opacity", seg(T, 3.4, 3.6)); note.setAttribute("transform", `translate(${500 + 80 * (1 - n)} 170) rotate(${4 + 10 * (1 - n)})`); + const f = touched ? flip(st, now) : 0; + squashX(paper, C, Math.abs(Math.cos(f * Math.PI))); + p1.setAttribute("display", f < 0.5 ? "inline" : "none"); p2.setAttribute("display", f < 0.5 ? "none" : "inline"); + }; + }, + }; + + /* ---- 3. a mixing desk: one slider up, one held down ---- */ + SC.mixer = { + dur: 7, still: 6, + build(svg, api) { + const root = el("g", {}, svg); + el("rect", { x: 70, y: 20, width: 660, height: 476, rx: 28, fill: SOFT, stroke: INK, "stroke-width": 3 }, root); + const TOP = 170, BOT = 320, LY = [108, 376]; + const ch = [ + { c: 230, name: "Your messages and use", lamp: "Used to train models", up: true, col: YEL }, + { c: 570, name: "Google Workspace data", lamp: "Not used to train", up: false, col: MINT }, + ]; + let sel = -1, selAt = -99, touched = false; + ch.forEach((s, i) => { + const g = el("g", {}, root), ly = LY[i], lt = s.up ? 66 : 432; + el("rect", { x: s.c - 8, y: TOP - 10, width: 16, height: BOT - TOP + 20, rx: 8, fill: "#fff", stroke: INK, "stroke-width": 2.5 }, g); + s.fill = el("rect", { x: s.c - 8, y: BOT, width: 16, height: 10, rx: 8, fill: BLUE, stroke: INK, "stroke-width": 2.5 }, g); + for (let k = 0; k <= 4; k++) { const y = TOP + (k * (BOT - TOP)) / 4; el("path", { d: `M${s.c - 54} ${y} H${s.c - 34} M${s.c + 34} ${y} H${s.c + 54}`, stroke: INK, "stroke-width": 2.5, "stroke-linecap": "round" }, g); } + s.rays = el("g", { opacity: 0 }, g); + for (let k = 0; k < 8; k++) { const a = ((k + 0.5) / 8) * Math.PI * 2; el("path", { d: `M${s.c + Math.cos(a) * 24} ${ly + Math.sin(a) * 24} L${s.c + Math.cos(a) * 32} ${ly + Math.sin(a) * 32}`, stroke: INK, "stroke-width": 3, "stroke-linecap": "round" }, s.rays); } + s.bulb = el("circle", { cx: s.c, cy: ly, r: 18, fill: "#fff", stroke: INK, "stroke-width": 3 }, g); + txt(g, s.c, lt, s.lamp, { "text-anchor": "middle", "font-size": 22 }); + txt(g, s.c, 474, s.name, { "text-anchor": "middle", "font-size": 22, "font-weight": 700 }); + s.knob = el("g", {}, g); + el("rect", { x: -38, y: -16, width: 76, height: 32, rx: 9, fill: "#fff", stroke: INK, "stroke-width": 3 }, s.knob); + el("path", { d: "M-22 0 H22", stroke: INK, "stroke-width": 3, "stroke-linecap": "round" }, s.knob); + ring(g, s.c - 150, 32, 300, 456, 22); + button(g, `${s.name}: ${s.lamp}`, () => { touched = true; sel = i; selAt = api.now(); api.poke(); }); + }); + const card = el("g", {}, svg); + el("rect", { x: 110, y: 508, width: 580, height: 84, rx: 22, fill: "#fff", stroke: INK, "stroke-width": 2.5 }, card); + txt(card, 400, 542, "Privacy policy, read 30 Oct 2026", { "text-anchor": "middle", "font-size": 20, "font-weight": 500, fill: MUTE }); + const line = txt(card, 400, 574, "", { "text-anchor": "middle", "font-size": 24, "font-weight": 700 }); + return (t, now) => { + const T = touched ? 6 : t; + root.setAttribute("opacity", 1 - seg(T, 6.6, 7)); + ch.forEach((s, i) => { + const v = s.up ? io(seg(T, 1.0, 3.0)) : 0, y = BOT - (BOT - TOP) * v; + tf(s.knob, s.c, y); s.fill.setAttribute("y", y); s.fill.setAttribute("height", BOT + 10 - y); + const lit = s.up ? seg(T, 2.9, 3.1) : seg(T, 3.5, 3.7), pop = ob(lit); + s.bulb.setAttribute("fill", lit > 0.5 ? s.col : "#fff"); + s.rays.setAttribute("opacity", lit > 0.5 ? 1 : 0); + s.rays.setAttribute("transform", `translate(${s.c} ${LY[i]}) scale(${0.6 + 0.4 * cl(pop, 0, 1.2)}) translate(${-s.c} ${-LY[i]})`); + }); + const k = sel < 0 ? 0 : RM ? 1 : oc(seg(now - selAt, 0, 0.35)); + card.setAttribute("opacity", k); card.setAttribute("transform", `translate(0 ${16 * (1 - k)})`); + line.textContent = sel < 0 ? "" : ch[sel].lamp; + }; + }, + }; + + /* ---- 4. six mailboxes, six ways in ---- */ + SC.mailboxes = { + dur: 8, still: 7, + build(svg, api) { + const root = el("g", {}, svg); + const BOX = [ + ["Poke", ["Text"], "No price in list", SKY, YEL], + ["Munder Difflin", ["Desktop", "and Slack"], "Free, open source", YEL, BLUE], + ["Folk", ["iMessage"], "Free, Pro $8.33 a month", LIL, YEL], + ["Martin", ["SMS and", "phone"], "From $21 a month", MINT, LIL], + ["Comma", ["Signal and", "Telegram"], "Free to start, open source", BLUE, YEL], + ["Maverick", ["iMessage"], "Free beta, Pro €27 a month", SKY, LIL], + ]; + const G = 352; + el("path", { d: `M30 ${G} H770`, stroke: INK, "stroke-width": 3, "stroke-linecap": "round" }, root); + let sel = -1, selAt = -99, touched = false; + const boxes = BOX.map(([name, tag, price, body, flag], i) => { + const cx = 72 + i * 125, g = el("g", {}, root), up = el("g", {}, g); + const nm = name.split(" "); + nm.forEach((w, j) => txt(up, cx, 150 - (nm.length - 1 - j) * 22, w, { "text-anchor": "middle", "font-family": MONO, "font-size": 18, "font-weight": 700 })); + el("rect", { x: cx - 7, y: 262, width: 14, height: G - 262, fill: "#fff", stroke: INK, "stroke-width": 3 }, up); + const fl = el("g", {}, up); + el("path", { d: `M0 0 V-40`, stroke: INK, "stroke-width": 3.5, "stroke-linecap": "round" }, fl); + el("path", { d: "M0 -40 H22 L16 -32 L22 -24 H0 Z", fill: flag, stroke: INK, "stroke-width": 2.5, "stroke-linejoin": "round" }, fl); + el("path", { d: `M${cx - 36} 264 V212 A36 36 0 0 1 ${cx + 36} 212 V264 Z`, fill: body, stroke: INK, "stroke-width": 3, "stroke-linejoin": "round" }, up); + el("path", { d: `M${cx - 16} 214 H${cx + 16}`, stroke: INK, "stroke-width": 4, "stroke-linecap": "round" }, up); + el("circle", { cx: cx + 36, cy: 238, r: 4, fill: INK }, up); + const tg = el("g", {}, g), tb = el("rect", { x: cx - 56, y: 372, width: 112, height: 60, rx: 14, fill: "#fff", stroke: INK, "stroke-width": 2.5 }, tg); + tag.forEach((w, j) => txt(tg, cx, 408 + (j - (tag.length - 1) / 2) * 21, w, { "text-anchor": "middle", "font-size": 17, "font-weight": 600 })); + ring(g, cx - 61, 108, 122, 330, 18); + button(g, `${name}: ${tag.join(" ")}. ${price}`, () => { touched = true; sel = i; selAt = api.now(); api.poke(); }); + return { cx, up, fl, tg, tb, g }; + }); + const card = el("g", {}, svg); + el("rect", { x: 100, y: 478, width: 600, height: 72, rx: 24, fill: SOFT, stroke: INK, "stroke-width": 2.5 }, card); + const line = txt(card, 400, 522, "", { "text-anchor": "middle", "font-size": 24 }); + const ln = el("tspan", { "font-family": MONO, "font-weight": 700 }, line), lp = el("tspan", { "font-weight": 500, dx: 14 }, line); + return (t, now) => { + const T = touched ? 7 : t; + root.setAttribute("opacity", 1 - seg(T, 7.6, 8)); + boxes.forEach((b, i) => { + const a = 0.2 + i * 0.15, k = ob(seg(T, a, a + 0.5)); + b.up.setAttribute("opacity", seg(T, a, a + 0.1)); + b.up.setAttribute("transform", `translate(0 ${G}) scale(1 ${Math.max(k, 0.001)}) translate(0 ${-G})`); + const f = 1.6 + i * 0.55, r = ob(seg(T, f, f + 0.45)); + b.fl.setAttribute("transform", `translate(${b.cx + 40} 248) rotate(${90 - 90 * r})`); + const q = oc(seg(T, f + 0.1, f + 0.45)); + b.tg.setAttribute("opacity", q); b.tg.setAttribute("transform", `translate(0 ${-14 * (1 - q)})`); + b.tb.setAttribute("fill", i === sel ? YEL : "#fff"); + }); + const k = sel < 0 ? 0 : RM ? 1 : oc(seg(now - selAt, 0, 0.35)); + card.setAttribute("opacity", k); card.setAttribute("transform", `translate(0 ${16 * (1 - k)})`); + if (sel >= 0) { ln.textContent = BOX[sel][0]; lp.textContent = BOX[sel][2]; } + }; + }, + }; + + /* ---- title card, 16 by 9 ---- */ + SC.hero = { + w: 960, h: 540, dur: 1, still: 0, + build(svg) { + el("rect", { x: 64, y: 84, width: 132, height: 38, rx: 19, fill: YEL, stroke: INK, "stroke-width": 2.5 }, svg); + txt(svg, 130, 110, "Concepts", { "text-anchor": "middle", "font-size": 19, "font-weight": 700 }); + txt(svg, 64, 222, "What is", { "font-size": 76, "font-weight": 700 }); + txt(svg, 64, 306, "Instinct AI?", { "font-size": 76, "font-weight": 700 }); + el("path", { d: "M66 334 H420", stroke: LIL, "stroke-width": 14, "stroke-linecap": "round" }, svg); + txt(svg, 64, 392, "Private beta, plus 6 alternatives", { "font-size": 27, "font-weight": 500, fill: MUTE }); + txt(svg, 64, 446, "Checked 30 Oct 2026", { "font-family": MONO, "font-size": 18, "font-weight": 500, fill: MUTE }); + const bub = (x, y, w, col, right) => { + const h = 70, r = 26, g = el("g", {}, svg); + const d = right + ? `M${x + r} ${y} H${x + w - r} Q${x + w} ${y} ${x + w} ${y + r} V${y + h - 6} Q${x + w} ${y + h} ${x + w - 6} ${y + h} H${x + r} Q${x} ${y + h} ${x} ${y + h - r} V${y + r} Q${x} ${y} ${x + r} ${y} Z` + : `M${x + r} ${y} H${x + w - r} Q${x + w} ${y} ${x + w} ${y + r} V${y + h - r} Q${x + w} ${y + h} ${x + w - r} ${y + h} H${x + 6} Q${x} ${y + h} ${x} ${y + h - 6} V${y + r} Q${x} ${y} ${x + r} ${y} Z`; + el("path", { d, fill: col, stroke: INK, "stroke-width": 3 }, g); + return g; + }; + bub(640, 136, 210, LIL, false); + [0, 1, 2].forEach((k) => el("circle", { cx: 690 + k * 26, cy: 171, r: 7, fill: INK }, svg)); + bub(660, 238, 236, BLUE, true); + el("rect", { x: 688, y: 262, width: 150, height: 10, rx: 5, fill: "#fff" }, svg); + el("rect", { x: 688, y: 282, width: 96, height: 10, rx: 5, fill: "#fff" }, svg); + bub(640, 340, 196, SKY, false); + el("circle", { cx: 680, cy: 375, r: 16, fill: MINT, stroke: INK, "stroke-width": 2.5 }, svg); + tickPath(svg, 680, 376, 0.9); + el("rect", { x: 708, y: 370, width: 100, height: 10, rx: 5, fill: "#fff" }, svg); + return () => {}; + }, + }; + + /* ---- player ---- */ + const q = new URLSearchParams(location.search), frozen = q.has("mgstill"), fixed = parseFloat(q.get("mgstill")); + const calm = RM; + 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/docs/blog/black-october-php2shell/index.html b/docs/blog/black-october-php2shell/index.html index 1b00fded4d..cb30904bdf 100644 --- a/docs/blog/black-october-php2shell/index.html +++ b/docs/blog/black-october-php2shell/index.html @@ -326,50 +326,50 @@

FAQ

Related in News

- +
- + 5 min
-

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

+

Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App

+

The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

+

Agent Tools Today, 26 Oct 2026: Kimi K3.1 Pro, Unified Claude Enterprise, ThinkRail

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents from 23 to 26 Oct 2026, each with its source.

News - Read → + Read →
- +
- + 5 min
-

Agent Tools Today, 22 Oct 2026: Claude API 2026-10-21, LayerFS 1.0, PHP2Shell

-

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 22 Oct 2026, each with its source.

+

Agent Tools Today, 23 Oct 2026: Claude Duet, OpenAI CLI, Nvidia OpenShell

+

The top launches, skills and MCP servers, multi agent moves, rising repos and arguments in coding agents on 23 Oct 2026, each with its source.

News - Read → + Read →
diff --git a/docs/blog/can-claude-code-agents-talk-to-each-other/index.html b/docs/blog/can-claude-code-agents-talk-to-each-other/index.html index 2a7f9f80a9..b2bd6a45ac 100644 --- a/docs/blog/can-claude-code-agents-talk-to-each-other/index.html +++ b/docs/blog/can-claude-code-agents-talk-to-each-other/index.html @@ -341,6 +341,22 @@

FAQ

Related in Concepts

+ -
diff --git a/docs/blog/claude-code-agent-teams/index.html b/docs/blog/claude-code-agent-teams/index.html index 23b4ce9fa7..2eb0ed14df 100644 --- a/docs/blog/claude-code-agent-teams/index.html +++ b/docs/blog/claude-code-agent-teams/index.html @@ -335,6 +335,22 @@

FAQ

Related in Concepts

+ -
diff --git a/docs/blog/claude-code-projects/index.html b/docs/blog/claude-code-projects/index.html index 1b81ead8d1..e99d7a8ac7 100644 --- a/docs/blog/claude-code-projects/index.html +++ b/docs/blog/claude-code-projects/index.html @@ -325,6 +325,22 @@

FAQ

Related in Concepts

+ -
diff --git a/docs/blog/claude-code-router/index.html b/docs/blog/claude-code-router/index.html index f11d81a0e2..2d74d4e488 100644 --- a/docs/blog/claude-code-router/index.html +++ b/docs/blog/claude-code-router/index.html @@ -314,6 +314,22 @@

FAQ

Related in Concepts

+ -
diff --git a/docs/blog/claude-code-routines/index.html b/docs/blog/claude-code-routines/index.html index dfb797ea9e..0d7f7e0007 100644 --- a/docs/blog/claude-code-routines/index.html +++ b/docs/blog/claude-code-routines/index.html @@ -353,6 +353,22 @@

FAQ

Related in Concepts

+ -
diff --git a/docs/blog/claude-haiku-5-5/index.html b/docs/blog/claude-haiku-5-5/index.html index 3a9702a797..45da389055 100644 --- a/docs/blog/claude-haiku-5-5/index.html +++ b/docs/blog/claude-haiku-5-5/index.html @@ -384,6 +384,22 @@

FAQ

Related in Concepts

+ -
diff --git a/docs/blog/claude-managed-agents-dynamic-workflows/index.html b/docs/blog/claude-managed-agents-dynamic-workflows/index.html index b1299531d8..8fb04cd151 100644 --- a/docs/blog/claude-managed-agents-dynamic-workflows/index.html +++ b/docs/blog/claude-managed-agents-dynamic-workflows/index.html @@ -338,6 +338,22 @@

FAQ

Related in Concepts

+ -
diff --git a/docs/blog/deepseek-v4-1-flash-1017/index.html b/docs/blog/deepseek-v4-1-flash-1017/index.html index 03030402e6..0be24f3383 100644 --- a/docs/blog/deepseek-v4-1-flash-1017/index.html +++ b/docs/blog/deepseek-v4-1-flash-1017/index.html @@ -390,6 +390,22 @@

FAQ

Related in Concepts

+ -
diff --git a/docs/blog/do-more-with-less-model-routing/index.html b/docs/blog/do-more-with-less-model-routing/index.html index fa83dc506e..583844779d 100644 --- a/docs/blog/do-more-with-less-model-routing/index.html +++ b/docs/blog/do-more-with-less-model-routing/index.html @@ -330,6 +330,22 @@

FAQ

Related in Concepts

+ -
diff --git a/docs/blog/feed.xml b/docs/blog/feed.xml index 2d4e0d4bc3..b1cd794f47 100644 --- a/docs/blog/feed.xml +++ b/docs/blog/feed.xml @@ -4,9 +4,25 @@ Guides, comparisons and pricing for AI agents and coding tools such as Claude Code, Codex and Cursor, each checked and dated. From the makers of Munder Difflin. - 2026-10-27T00:00:00.000Z + 2026-10-30T00:00:00.000Z https://munderdiffl.in/blog/ Chaitanya Girihttps://munderdiffl.in + + Agent Tools Today, 30 Oct 2026: Mistral Large 4 Weights, Claude Code 2.1.314, Herdr App + + https://munderdiffl.in/blog/agent-tools-today-2026-10-30/ + 2026-10-30T00:00:00.000Z + 2026-10-30T00:00:00.000Z + The top launches, skills, multi agent moves, rising repos and arguments in AI agents from 29 to 30 Oct 2026, each with its source and date. + + + What Is Instinct AI? Access, Privacy and 6 Alternatives You Can Use Now (Oct 2026) + + https://munderdiffl.in/blog/what-is-instinct-ai/ + 2026-10-30T00:00:00.000Z + 2026-10-30T00:00:00.000Z + Instinct is a personal AI agent you text or call, still in private beta. What it does, what its privacy policy says, and six texting agents you can use today. + GPT-6.1 Terra: Price, Specs and How to Use It in Codex (Oct 2026) @@ -471,20 +487,4 @@ 2026-10-08T00:00:00.000Z The top launches, skills and plugins, multi agent moves, rising repos and arguments in coding agents on 8 Oct 2026, each with its source. - - Claude Code agent teams: what they are, how to use them - - https://munderdiffl.in/blog/claude-code-agent-teams/ - 2026-10-08T00:00:00.000Z - 2026-10-08T00:00:00.000Z - Claude Code agent teams, checked 8 Oct 2026: what they are, the experimental setting that turns them on, how they differ from subagents, token cost and limits. - - - Claude Haiku 5.5: price, benchmarks and where it fits - - https://munderdiffl.in/blog/claude-haiku-5-5/ - 2026-10-08T00:00:00.000Z - 2026-10-08T00:00:00.000Z - 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. - diff --git a/docs/blog/gemini-4-argon-inside-google/index.html b/docs/blog/gemini-4-argon-inside-google/index.html index 660bbc903f..9498a3c197 100644 --- a/docs/blog/gemini-4-argon-inside-google/index.html +++ b/docs/blog/gemini-4-argon-inside-google/index.html @@ -266,6 +266,22 @@

FAQ

Related in Concepts

+ -
diff --git a/docs/blog/gemini-4-argon/index.html b/docs/blog/gemini-4-argon/index.html index 7e1431f9f2..37900c40cc 100644 --- a/docs/blog/gemini-4-argon/index.html +++ b/docs/blog/gemini-4-argon/index.html @@ -407,6 +407,22 @@

FAQ

Related in Concepts

+ -
diff --git a/docs/blog/generative-engine-optimization-techniques/index.html b/docs/blog/generative-engine-optimization-techniques/index.html index 31959b04f5..df660d69f5 100644 --- a/docs/blog/generative-engine-optimization-techniques/index.html +++ b/docs/blog/generative-engine-optimization-techniques/index.html @@ -335,6 +335,22 @@

FAQ

Related in Concepts

+ -
diff --git a/docs/blog/gpt-6-1-terra/index.html b/docs/blog/gpt-6-1-terra/index.html index 8417454557..0bb49710c1 100644 --- a/docs/blog/gpt-6-1-terra/index.html +++ b/docs/blog/gpt-6-1-terra/index.html @@ -378,56 +378,56 @@

FAQ