uvの--lockedと--frozenを検証する:CIの同期成功は何を保証するか
uv sync --frozenが成功しても、pyproject.tomlへ追加した依存が入っているとは限りません。
小さなプロジェクトでlockfileの更新漏れを作ったところ、--lockedはエラーで止まり、--frozenは成功しました。ただし後者では、新しく追加したidnaをimportできる状態になっていませんでした。
この記事では、この差を再現し、CI(変更のたびにテストなどを実行する仕組み)で何を検証したいかから指定を選びます。実測環境はLinux、uv 0.11.19、Python 3.12.3です。GitHub Actions自体は実行していません。
lockfileが一致していない状態を作る
既存プロジェクトを壊さないよう、空の検証用ディレクトリで行います。uvと、次の条件を満たすPythonが使えることが前提です。
最初のpyproject.tomlは次の内容です。ビルド設定を持たない小さな検証用プロジェクトで、アプリの配布は行いません。
[project]
name = "uv-ci-example"
version = "0.1.0"
requires-python = ">=3.12,<3.13"
dependencies = ["packaging>=24,<26"]
[dependency-groups]
dev = ["pytest>=8,<9"]
比較対象のPython系統をそろえてから、最初のlockを作る
uv python pin 3.12
uv lock
uv sync --locked
ここではpyproject.tomlとuv.lockが整合しています。lockfileは、解決済みの依存関係を記録したファイルです。pyproject.tomlが求める条件と、実際に使う解決結果を別々に扱えるようになります。uvのプロジェクト構成
続いて、pyproject.tomlのdependencies行だけを次へ変更します。
lock更新漏れを再現するため、この段階ではuv addを使わない
dependencies = ["packaging>=24,<26", "idna==3.10"]
この行は既存の[project]内にある行を置き換えるものです。別の場所へ追記しないでください。通常の依存追加にはuv addを使えますが、今回は意図的にuv.lockを更新しない状態を作っています。uvの依存関係管理
--lockedでは更新漏れを検出できた
設定とlockの不整合を検出できるか確認する
uv sync --locked
実測では終了コード1になり、lockfileの更新が必要なのに--lockedが指定されている、というエラーになりました。uv.lockの内容は変更されていません。
これは想定した失敗です。CIに「コミットされた依存設定を、そのlockfileで扱えるか」を検証させたいなら、この段階で止まることに意味があります。
--frozenは成功したが、追加依存は入らなかった
同じ状態のまま、今度は次を実行しました。
不整合な設定を保ったまま、既存lockを使った場合を比較する
uv sync --frozen
通常のuv runによる自動更新を避け、未導入の状態を調べる
uv run --frozen python -c "import importlib.util; assert importlib.util.find_spec('idna') is None"
両コマンドとも終了コード0でした。2つ目のコマンドが成功したことは、この環境でidnaが見つからなかったことを意味します。uv.lockも変更されていません。
確認時にuv runへ--frozenを付けたのは、観測中にlockや環境が自動更新されるのを避けるためです。通常のuv runには、コマンドの起動前に必要なlockと同期を行う動作があります。uvのlockと同期
2つの指定は、確認する条件が違う
図:公式仕様と本記事の検証を基に独自作成。GitHub上の実行画面ではありません。
操作
今回の不整合への動作
成功から読み取れること
uv sync --locked
更新が必要なので停止
成功した場合、uvの判定でlockが現在の設定と整合している
uv sync --frozen
整合性確認を省き、古いlockで同期
選ばれたlockと同期対象のグループで環境を作れた。現在の設定との整合性は別途確認が必要
uv lockの後にuv sync --locked
lockを更新してから同期
更新した解決結果を使って環境を作れる
--frozenは「より厳しい固定」という意味ではなく、lockfileの最新性確認を省く指定です。仕様はLocking and syncingに記載されています。
また、--lockedもファイルの文字列が完全一致するかを検査するものではありません。たとえば依存の条件を変えても、既存lockが引き続き条件を満たす場合があります。新しいパッケージ版が公開されたことだけで、lockが不整合になるわけでもありません。
このため、通常のCIでは--lockedを出発点にし、別工程で整合性を保証しているなどの理由がある場合に--frozenを選ぶ、という整理ができます。
更新する工程と、検証する工程を分ける
先ほどの検証用プロジェクトでは、次の操作で不整合を解消できます。
依存変更をlockへ反映し、差分をレビューできる状態にする
uv lock
uv sync --locked
更新後には追加した依存が見つかることを確認する
uv run --locked python -c "import importlib.util; assert importlib.util.find_spec('idna') is not None"
CIへ渡すときは、pyproject.tomlとuv.lockの両方をGitで管理します。通常のテスト実行中にlockを作り直すより、依存を変更する作業で更新し、その差分を確認してからCIへ渡す方が、何をテストしたかを追いやすくなります。
pytestをdevグループに登録したプロジェクトなら、uvとPythonの準備後のテスト部分は次のようになります。これはjobs.<job_id>.steps内の断片です。
- name: Sync dependencies
CI内の暗黙のlock更新で、更新漏れが隠れるのを防ぐ
run: uv sync --locked
- name: Run tests
テスト起動時にも同じ整合性条件を保つ
run: uv run --locked pytest -q
uv runにも--lockedを付けることで、実行直前の自動更新に頼らず検証します。tests/にはプロジェクトのテストを用意してください。上の依存設定と同期だけでは、テストケースは生成されません。uvのGitHub Actions連携
lockfileだけで実行環境全体が固定されるわけではない
図:公式仕様と本記事の検証を基に独自作成。GitHub上の実行画面ではありません。
ローカル検証では、pytest 8.4.2とpackaging 25.0を導入し、バージョンの順序を比較するテスト3件を実行しました。検証用の.venvを削除して再同期した後も、同じ3件が成功しました。依存追加後にlockを更新した後も成功しています。
ただし、これはGitHubのrunner(ジョブを実行するマシン)でも同じ挙動になることをすべて確認した結果ではありません。
対象
そろえる方法
注意点
依存関係
uv.lockを共有し、--lockedで同期
OSやPython条件により導入対象が変わり得る
uv本体
setup-uvのversion入力などで指定
Actionの版だけではuv本体まで固定されない
Python
CIと手元で同じ版を選択
3.12指定ではパッチ版まで一致するとは限らない
OS
対象runnerを選ぶ
同じOSラベルでもイメージ内部は更新される
Pythonの選択とuv本体の導入方法は、uvのPythonバージョン管理とsetup-uvの入力設定を参照してください。
キャッシュヒットでもsyncは必要
キャッシュは取得・ビルド済みの成果物を再利用する仕組みです。今回必要なパッケージを決めるlockfileや、その内容から環境を作る同期処理の代わりにはなりません。uvのキャッシュ
キャッシュが復元できてもuv sync --lockedは実行し、今回の環境を整えます。逆にキャッシュがない初回でも、必要なパッケージを取得できればテストまで進める構成にします。
私は、CIでの再現性は「固定するファイルを増やす」だけでなく、どの不整合をエラーにするかを決めることが大事だと考えています。今回の例では、--frozenで同期できたことより、--lockedが更新漏れを検出したことの方が、依存変更をレビューする目的に合っていました。
公式資料の確認日は2026年9月11日です。ローカルでの同期・不整合検出・テストを確認し、GitHub Actionsのイベント発火、Actionの実行、キャッシュ復元と速度は未検証として区別しています。
uvのプロジェクト管理へ移るところから確認したい場合は、uvとpip・venvの違いと移行手順も参照してください。
GitHub Actionsへ導入するためのworkflow全体と、Python・uvの固定、キャッシュ、サブディレクトリの設定は、uvをGitHub Actionsで使う方法にまとめています。
OpenAI, Hugging Face, Google: Why They All Reach for Rust
OpenAI rewrote Codex CLI in Rust. Hugging Face's tokenizers, safetensors, uv and Ruff all run on Rust. Why does a Python world keep reaching for it? The problem Rust solves (speed or safety), where it already runs in AI, what it honestly costs, and the plan for this series: Rust from zero, one picture at a time.
Chapters
0:00 AI keeps reaching for Rust
0:46 The problem: speed or safety
1:34 What Rust does differently
2:03 Does it work? Android's numbers
2:40 Where Rust runs in AI today
4:04 Is Rust replacing Python?
4:29 The honest cost
4:59 The plan: two playlists
5:28 What would you build?
Next: Episode 1: Your first Rust program
The whole series, in order: Learn Rust from Zero (Beginners) · Rust You Can See (playlist)
Sources
- OpenAI Codex CLI rewrite: codex#1174
- Hugging Face tokenizers: huggingface/tokenizers
- safetensors joins the PyTorch Foundation: pytorch.org
- uv: astral-sh/uv · Ruff: astral-sh/ruff
- Astral agrees to join OpenAI: astral.sh
- Microsoft, ~70% of CVEs are memory safety: microsoft.com
- Chromium memory safety: chromium.org
- Android memory safety: security.googleblog.com · blog.google
- The Case for Memory Safe Roadmaps (2023): cisa.gov
- Linux 6.1 (Rust support): kernelnewbies.org
- Stack Overflow 2025 survey: survey.stackoverflow.co
- GitHub Octoverse 2025: github.blog
- TypeScript's native port in Go: devblogs.microsoft.com
- Rust compiler performance survey 2025: blog.rust-lang.org
- Pydantic core: pydantic/pydantic-core · Polars: pola.rs
Ferris the crab is the Rust community's mascot (public domain, rustacean.net).
Rust You Can See is an independent series, not affiliated with or endorsed by the Rust Project or the Rust Foundation. Rust is a trademark of the Rust Foundation.
Narration: AI-generated voices.
#rust #learnrust #programming
[es] Por qué la IA se está pasando a Rust
[fr] Pourquoi l'IA se tourne vers Rust
[hi] AI अब Rust पर क्यों शिफ्ट हो रहा है?
[ja] なぜAIはRustへ移行しているのか
[ko] AI가 Rust로 옮겨가는 이유
[pt-BR] Por que a IA está migrando para Rust
4 likes · 1 comment · 352 views
@thsottiaux Yes
ruff#29852
20 likes · 17,440 views
Tinyworldformer corre en un Pico 2W de $6 con 520 KB de RAM
Un microcontrolador de 6 dólares acaba de ejecutar, en tiempo real, un modelo de mundo comprimido que inventa videojuegos cuadro por cuadro. El proyecto tinyworldformer corre dentro de 520 KB de RAM en una Raspberry Pi Pico 2W, sin GPU, sin nube y sin conexión a internet.
Su autor lo logró separando el trabajo en dos redes neuronales por fotograma. Una genera el siguiente cuadro del juego, la otra decide qué botón presionar, y ambas corren a la vez sobre el mismo chip.
TL;DR
- Int8 y pesos compartidos reducen el generador de frames a entre 26.000 y 131.000 parámetros según el juego.- Un bloque transformer aplicado de 1 a 4 veces sustituye a una pila de capas distintas y ahorra memoria.- La red actora, separada del generador, pesa solo entre 9.000 y 16.000 parámetros en float32.- El RP2350 reparte el trabajo: el núcleo 1 corre ambas redes, el núcleo 0 atiende USB y pantalla.- El repositorio SheepSeb/tinyworldformer deja jugar los cinco juegos reales desde la terminal con uv.
¿Qué es un modelo de mundo comprimido?
Un modelo de mundo comprimido es una red neuronal generativa reducida en tamaño y precisión para correr sin GPU: tinyworldformer la implementa como un transformer en bucle cuantizado a 8 bits que predice el siguiente fotograma de un videojuego y cabe en los 520 KB de RAM de un microcontrolador de 6 dólares.
La idea de partida de su autor fue simple. Los transformers en bucle reutilizan el mismo bloque de pesos varias veces en lugar de apilar capas distintas, así que ocupan mucha menos memoria por diseño. Si ese ahorro era suficiente, un modelo generativo completo podía caber en un chip de bolsillo.
Por qué importa
La mayoría de los modelos generativos de video o de juegos dependen de una GPU con varios gigabytes de memoria. Tinyworldformer invierte esa ecuación: corre en un chip pensado para termostatos y drones de juguete. Eso importa para el campo conocido como edge computing, donde el objetivo es mover la inferencia al dispositivo en lugar de depender de un servidor remoto.
Un modelo que corre en el borde no necesita conexión a internet, no paga latencia de red y no expone datos a un servidor externo. Acá el beneficio es además una prueba de concepto. Si una red generativa cabe en 520 KB, la pregunta deja de ser si el edge AI puede generar contenido y pasa a ser cuánto contenido puede generar con ese presupuesto de memoria.
El ángulo de costo pesa tanto como el técnico. Una Raspberry Pi Pico 2W cuesta una fracción de lo que cuesta cualquier GPU capaz de correr un transformer completo, y consume órdenes de magnitud menos energía porque no tiene memoria de video ni refrigeración activa. Para proyectos de hobby, educación o investigación en TinyML, esa diferencia de costo decide si un experimento se hace o no.
Cómo funciona tinyworldformer por dentro
Tinyworldformer separa el problema en dos redes con trabajos distintos. La primera, el generador de frames, recibe el cuadro actual y la acción del jugador y predice el cuadro siguiente junto con la recompensa. La segunda, la red actora, solo mira el cuadro y decide qué acción tomar. Ninguna de las dos ve jamás el juego real una vez que arranca la sesión: el generador solo recibe acciones de la actora, y la actora solo ve cuadros inventados por el generador.
sequenceDiagram
participant Actor as Red actora
participant Generador as Generador de frames
Actor->>Generador: envia accion
Generador-->>Actor: entrega frame generado y recompensa
Note over Actor,Generador: el generador nunca ve el juego real
Tokenización en parches
Antes de entrar al transformer, cada cuadro se recorta en parches cuadrados: 2x2 celdas en Breakout, 4x4 en Doom-lite, Flappy Bird y Pong, 6x6 en Pac-Man lite. Eso da entre 36 y 80 tokens por juego según el repositorio. Cada token suma un vector aprendido por celda, con una tabla distinta según la posición dentro del parche para no perder el orden, más un vector de posición y un vector de la acción tomada.
Un ejemplo simplificado en Python muestra la misma idea con un cuadro diminuto de 4x4 dividido en parches de 2x2:
import numpy as np
frame = np.array([
[1, 1, 2, 2],
[1, 1, 2, 2],
[3, 3, 4, 4],
[3, 3, 4, 4],
])
def a_parches(frame, parche=2):
h, w = frame.shape
tokens = []
for i in range(0, h, parche):
for j in range(0, w, parche):
tokens.append(frame[i:i+parche, j:j+parche].flatten())
return np.array(tokens)
print(a_parches(frame))
La salida literal es una matriz de 4 tokens, uno por cada región homogénea del cuadro:
[[1 1 1 1]
[2 2 2 2]
[3 3 3 3]
[4 4 4 4]]
El transformer en bucle
En lugar de apilar, por ejemplo, ocho bloques transformer distintos, tinyworldformer usa un único bloque (atención más una red feedforward con ReLU) y lo aplica entre 1 y 4 veces seguidas, sumando la entrada original antes de cada pasada. El resultado de cada pasada se entrena contra el cuadro siguiente real, así que el número de pasadas en tiempo de ejecución es un control directo entre velocidad y precisión. En el Pico 2W, para mantener una tasa de cuadros razonable, el proyecto usa dos pasadas.
flowchart TD
A["Frame t + accion"] --> B["Tokenizar en parches"]
B --> C["Bloque transformer (pesos compartidos)"]
C --> D{"Repetir de 1 a 4 veces"}
D -->|"otra pasada"| C
D -->|"pasada final"| E["Frame t+1 y recompensa"]
Cuantización y reparto entre núcleos
El generador de frames se cuantiza a int8, mientras que la red actora se queda en float32 porque ya es pequeña de por sí, entre 9.000 y 16.000 parámetros, y la precisión ahí importa más para decidir bien la acción. El RP2350 del Pico 2W tiene dos núcleos: el núcleo 1 corre el generador y la actora, el núcleo 0 se encarga del USB y de la pantalla, según documenta el repositorio.
Esa separación entre generador y actor permite optimizar cada red por separado. El generador, la parte pesada, recibe toda la cuantización, mientras que la actora, ya liviana, se queda intacta en float32.
El RP2350 integra FPU, pieza clave para ejecutar redes cuantizadas.
flowchart TD
A["RP2350 dual-core"] --> B["Nucleo 0: USB y pantalla"]
A --> C["Nucleo 1: inferencia"]
subgraph Inferencia["Nucleo de inferencia"]
C --> D["Generador de frames int8"]
C --> E["Red actora float32"]
end
Ejemplos prácticos y cómo empezar
El repositorio incluye cinco juegos reales escritos en unas pocas líneas de numpy, lo que le permite a su autor comparar cada frame generado contra la física real del juego. La siguiente tabla resume el costo de memoria y cómputo de cada uno, con datos publicados en el repositorio de tinyworldformer:
JuegoTamaño de frameParámetrosMACs por frameFrames exactosBreakout20x1626k4.3M99.99%Doom-lite32x3255k4.2M83.6%Flappy Bird24x2446k2.0M100%Pong20x3246k2.3M99.45%Pac-Man lite48x48131k8.2M86.4%
La columna de frames exactos mide el porcentaje de transiciones donde cada celda del cuadro predicho coincide con el cuadro real. Doom-lite tiene el número más bajo, 83.6%, pero no porque juegue mal: su vista en primera persona tiene 768 celdas, y un solo píxel de sombra mal pintado ya marca todo el cuadro como incorrecto en esta métrica.
Cómo probarlo en tu máquina
El proyecto usa uv como gestor de paquetes de Python, así que no hace falta instalar dependencias a mano una por una. En Linux o macOS:
curl -LsSf https://astral.sh/uv/install.sh | sh
git clone https://github.com/SheepSeb/tinyworldformer
cd tinyworldformer
uv run python -m tinyworldformer.games.play --game pacman
En Windows, el único paso que cambia es la instalación de uv, desde PowerShell: powershell -c "irm https://astral.sh/uv/install.ps1 | iex", y luego los mismos comandos de git clone y uv run.
El comando play acepta también breakout, doomlite, flappy o pong en lugar de pacman. No hay salida de texto que mostrar: uv descarga las dependencias declaradas en el pyproject.toml y abre una ventana gráfica con el juego real corriendo en numpy, el mismo que el generador de frames aprendió a imitar.
> 💡 Tip: correr primero el juego real con play antes de buscar los pesos entrenados ayuda a entender qué está tratando de imitar el generador cuantizado, celda por celda.
Casos de uso reales
Tinyworldformer no apunta a reemplazar un motor de videojuegos. Su valor está en lo que demuestra: un modelo generativo entrenado sobre partidas grabadas puede, cuantizado y comprimido, correr en el mismo chip que hoy maneja sensores de temperatura o drones de juguete baratos. El caso de uso inmediato es educativo y de investigación en TinyML, pero la receta (tokenizar en parches, compartir pesos entre pasadas, cuantizar solo la parte más pesada) es trasladable a otros generadores pequeños, como un simulador de sensor para probar un controlador embebido sin hardware real conectado.
El repositorio también suma un agente de refuerzo por streaming que aprende a jugar dentro del sueño generado por el propio modelo, en lugar de solo repetir una política ya entrenada. Cualquier botón del dispositivo le devuelve el control al usuario humano, así que la misma placa sirve para ver a la IA jugar sola o para jugar uno mismo dentro del mundo que ella inventa.
Breakout necesita solo 26.000 parámetros; Pac-Man lite necesita 131.000.
Errores comunes y buenas prácticas
- Confundir precisión de píxel con jugabilidad. Un 83.6% de frames exactos suena mal hasta que se entiende la métrica: un solo píxel de sombra distinto ya cuenta como fallo total del cuadro, aunque el estado del juego (posición del enemigo, vida, puntaje) siga siendo correcto.- Cuantizar todo por igual. Aplicar int8 a la red actora, que ya tiene menos de 16.000 parámetros, aportaría poco ahorro de memoria y arriesgaría la precisión de la política. La cuantización rinde donde el modelo es grande, no donde ya es pequeño.- Elegir mal el número de pasadas del bucle. Una sola pasada del transformer es más rápida pero deja artefactos visibles, un enemigo que no debería estar ahí, por ejemplo. Cuatro pasadas corrigen casi todo el error pero cuestan más tiempo de cómputo por cuadro. Dos pasadas fue el punto que eligió el proyecto para el Pico 2W.- Verificar contra la física real, no solo mirar el video generado. Tener la versión real del juego en numpy, como hace este repositorio, es lo que permite medir el error cuadro por cuadro en lugar de confiar en que se vea bien.
Comparativa con alternativas para generar contenido con IA
EnfoqueCuándo usarloVentajaLimitaciónTransformer completo en GPU o nubeCuando la latencia de red no importa y hay presupuesto de cómputoMáxima fidelidad del frame generadoDepende de conexión e infraestructura externaModelo de mundo comprimido en microcontrolador (tinyworldformer)Dispositivos aislados, sin GPU, con RAM y flash muy limitadosCorre offline, sin latencia de red, consumo mínimoSolo viable en juegos o dominios muy pequeñosDistillation genérica a modelos pequeños (TinyML clásico)Tareas de clasificación o detección simples en sensoresHerramientas y runtimes madurosNo pensado para generar secuencias completas de frames
La fila intermedia describe a tinyworldformer. No busca competir en fidelidad visual con un generador de video entrenado en GPU; busca que el juego siga siendo jugable dentro de un presupuesto de memoria minúsculo.
Profundizando: por qué el bucle ahorra memoria y dónde se nota el límite
La razón de fondo por la que un transformer en bucle pesa menos es aritmética simple: un transformer tradicional de N capas guarda N juegos de pesos distintos, mientras que el bucle guarda un solo juego de pesos y lo reusa N veces. El costo que se paga a cambio es tiempo de cómputo, cada pasada adicional cuesta los mismos multiplica-acumula que la anterior, en lugar de memoria, y en un microcontrolador la memoria suele ser el recurso más escaso de los dos.
La cuantización int8 agrega un segundo ahorro, independiente del anterior: cada peso pasa de ocupar 4 bytes en float32 a ocupar 1 byte, a costa de redondear cada valor a uno de 256 niveles posibles. El siguiente ejemplo en Python muestra ese redondeo con cuatro pesos cualquiera:
import numpy as np
pesos = np.array([0.42, -0.87, 1.35, -1.90], dtype=np.float32)
escala = np.max(np.abs(pesos)) / 127
cuantizados = np.round(pesos / escala).astype(np.int8)
reconstruidos = cuantizados.astype(np.float32) * escala
print(cuantizados)
print(np.round(reconstruidos, 4))
La salida literal es:
[ 28 -58 90 -127]
[ 0.4189 -0.8678 1.3465 -1.9 ]
El peso original de 1.90 se reconstruye exacto porque definió la escala; los otros tres cargan un pequeño error de redondeo. Ese error, multiplicado por miles de pesos y varias pasadas del bucle, ayuda a explicar por qué Pac-Man lite, el juego más complejo con 131.000 parámetros, tiene un porcentaje de frames exactos menor que Flappy Bird. No hay una forma directa de verificar desde afuera, sin acceso al checkpoint, cuánto de ese error viene de la cuantización y cuánto del tamaño del juego; lo más cercano que ofrece el propio repositorio es comparar el porcentaje de frames exactos por juego de la tabla anterior.
El FPU del RP2350 importa en este punto. Sin una unidad de punto flotante en hardware, la dequantización, volver de int8 a valores reales antes de cada operación de atención, sería mucho más lenta, porque el chip tendría que emular esas operaciones en software.
> 💭 Clave: el ahorro de memoria del bucle y el ahorro de la cuantización son independientes entre sí; tinyworldformer los combina, pero cada uno podría usarse por separado en otro proyecto.
📖 Resumen en Telegram: Ver resumen
Tu próximo paso: cloná el repositorio, corré uv run python -m tinyworldformer.games.play --game breakout y leé el archivo de ese juego dentro de src/tinyworldformer/games/ para ver cuántas líneas de numpy hacen falta para una física jugable completa.
Preguntas frecuentes
¿Qué microcontrolador corre el modelo de mundo comprimido de tinyworldformer?
Una Raspberry Pi Pico 2W, construida sobre el chip RP2350, que tiene dos núcleos y una unidad de punto flotante. El núcleo 1 ejecuta el generador de frames y la red actora; el núcleo 0 atiende USB y la pantalla.
¿Cuántos parámetros tiene el transformer en bucle de cada juego?
Entre 26.000 y 131.000, según la complejidad del juego: Breakout es el más liviano y Pac-Man lite el más pesado, de acuerdo con la tabla publicada en el repositorio.
¿Hace falta GPU para entrenar tinyworldformer antes de cuantizarlo?
El repositorio no detalla el hardware exacto de entrenamiento, pero el generador de frames se entrena sobre partidas grabadas del juego real, un proceso que normalmente se hace fuera del microcontrolador y antes de cuantizar los pesos para desplegarlos en el Pico 2W.
¿Qué diferencia a la red actora de la IA embebida en microcontroladores que genera los frames?
La red actora es una MLP mucho más chica, entre 9.000 y 16.000 parámetros, que se queda en float32 porque su tarea, decidir una acción a partir de un frame, tolera peor el error de cuantización que generar el frame en sí.
¿Se puede correr tinyworldformer en un microcontrolador distinto al Pico 2W?
El repositorio está construido específicamente para el RP2350 del Pico 2W, incluyendo una carpeta en Rust para el firmware del dispositivo. Portarlo a otro chip exigiría al menos una FPU y memoria suficiente para los buffers de atención, pero el propio proyecto no documenta otros objetivos probados.
Referencias
- GitHub: SheepSeb/tinyworldformer: repositorio original con el código, los juegos en numpy y los datos de tamaño y precisión de cada modelo.- Raspberry Pi: fabricante oficial de la Raspberry Pi Pico 2W y el chip RP2350 usado en el proyecto.- Wikipedia: Edge computing: contexto sobre mover la inferencia de IA al dispositivo en lugar de a un servidor remoto.- Wikipedia: Quantization: fundamento matemático de la cuantización usada para pasar los pesos de float32 a int8.
📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.
It depends who you trust :slight_smile:
Astral/OpenAI build binaries at Python Build Standalone:
astral-sh/python-build-standalone
These are used by projects such as uv, Hatch and PDM.
1 like
> why this exists
docs.basedpyright.com
> The "type server protocol" is a desperate attempt from microsoft to prevent pylance from becoming obsolete by outsourcing its type checking to other language servers like basedpyright, ty or pyrefly -- while continuing to keep certain language server features exclusive to pylance.
> This protocol benefits nobody except microsoft. It adds needless complexity to any language server that chooses to support it. Basedpyright does not support it and strongly advises other language servers to avoid supporting it as well.
> For more info see here pylance-release#7180 and here ty#1190
DetachHead (maintainer of basedpyright) has criticized the TSP before:
- docs.basedpyright.com
- pylance-release#7180
Ty (the type checker maintained by astral) however will apparently support the TSP: ruff#23432
Rust Didn't Win Because It's Fast
GitHub rewrote Copilot's runtime in Rust. OpenAI's Codex is now almost all Rust. Bun, the runtime Claude Code ships on, moved 535,496 lines of Zig to Rust in 11 days. But it isn't about speed: C has been fast for half a century. We fly inside a real laptop, down to the CPU die and the memory cells, to show what Rust actually changed, and why AI coding agents love it.
0:00 Everyone is rewriting in Rust
0:49 This is Sidequest Explained
1:00 Inside the machine: instructions, bytes, stack and heap
1:53 Way one: freeing memory by hand (C and C++)
2:23 An elevator crash started Rust
2:40 Way two: the garbage collector (Discord's spikes)
3:12 Way three: ownership
3:36 Checked before it runs, and Android's results
4:07 Close to the metal: 28 bytes vs 8
4:21 Copilot: 5.25 s to 292 ms
4:41 Why AI agents love the Rust compiler
5:11 Is Python dead? What it means for you
Sources
GitHub Blog, migrating the Copilot runtime to Rust (Sep 2026): github.blog
Bun, Rewriting Bun in Rust (Jul 2026): bun.sh
OpenAI Codex repository: openai/codex
Codex native rewrite discussion: codex#1174
Grok Build repository: xai-org/grok-build
Dennis Ritchie, The Development of the C Language: bell-labs.com
Microsoft MSRC, 70% of security bugs are memory safety (2019): microsoft.com
Chromium memory safety: chromium.org
MIT Technology Review, Rust's origin (2023): technologyreview.com
Rust 1.0 announcement: blog.rust-lang.org
Discord, Why Discord is switching from Go to Rust (2020): discord.com
The Rust Book, ownership and borrowing: doc.rust-lang.org
Google, memory-safe languages in Android 13 (2022): security.googleblog.com
Google, Rust in Android (Nov 2025): blog.google
Python sys.getsizeof / CPython ints: docs.python.org
Hugging Face tokenizers: huggingface/tokenizers
OpenAI tiktoken: openai/tiktoken
pydantic-core: pydantic/pydantic-core
uv by Astral: astral-sh/uv
Numbers are the sources' own. The Copilot timings are client + session + one-turn overhead in the opt-in in-process mode, not counting the model or network. Android's 1000× is memory-safety vulnerability density. Code on screen is an illustration, not a run.
Credits
Die micrographs: Fritzchens Fritz (CC0). Memory-cell micrograph (Micron MT4C1024) and SEM plate (1886VE10): ZeptoBars, CC BY 3.0. Office and hardware photos: Pexels. HDRIs and materials: Poly Haven, ambientCG (CC0). Music: "Lofi Study" by FASSounds (Pixabay). Rust, GitHub, Copilot, OpenAI, Codex, Bun, Claude, xAI, Grok, Microsoft, Chrome, Android, Discord, Python, Hugging Face, Astral, pydantic and other names and logos belong to their owners, used for identification and commentary; Sidequest is not affiliated with any of them. Narration: an AI clone of my own voice. Animation: original, built in three.js.
#rust #programming #ai
50 likes · 14 comments · 6,610 views
uv Now Type-Checks Python with ty. How to Set Up uv check (Pin ty First)
uv now has a type-check command. uv check syncs your project environment, downloads the ty type checker and runs it, with no config and no separate pip install. It also checks PEP 723 scripts against their own inline dependencies, which is the part that got me: your type checker has probably been checking those scripts against the wrong venv for years, flagging import requests as unresolved or silently using whatever happened to be installed.
I've been running it and I like it. The "your laptop and CI use the same ty version" pitch needs a footnote, though, and one command fixes it.
I'll go through projects first, then workspaces, scripts, VS Code, pre-commit and GitHub Actions.
What uv check actually does
Per the announcement from October 13, 2026, uv check prepares the project environment, installs its dependencies and checks the project with ty. You need uv 0.12.3 or later and ty 0.0.76 or later. ty itself gets downloaded the first time you run the command, so you don't install it yourself.
It's a preview feature. Astral says so plainly, and if you never run uv check, nothing about your uv workflow changes.
The CLI reference describes it as "Run checks on the project," and adds: "Currently, this type checks Python code using ty." There's also a --fix flag to apply safe fixes. Ruff is on the roadmap but not in the command yet. Frank Chu tested this by adding unused import os and import sys: uv check didn't report either of them. So keep your ruff check step for now.
Step 1: type-check a project with uv check
uv self update # make sure you're on 0.12.3+
uv check
That's the whole setup. On the first run in Chu's test (uv 0.13.5, ty 0.0.91, a 2 vCPU VM), uv created .venv, pulled a managed CPython, built the project and downloaded ty, which was 13.5 MiB. The cold run took 5.53s and warm runs took 0.71s. Bare ty check on the same tiny project took 0.09s, so ty barely registers and most of the time goes to uv syncing the environment.
The exit codes are what CI expects: 1 when there are diagnostics, 0 when the code is clean.
Every run prints an experimental warning. Chu found you can silence it with --preview-features check-command.
Step 2: workspaces with --package and --all-packages
If you use a uv workspace, the flags work the same way they do in uv sync:
uv check --package api # one member: syncs it + its deps, checks only its files
uv check --all-packages # every member in the workspace
The reference docs say --package syncs the workspace environment with the selected members and their dependencies, and "only files owned by those members are checked." In a monorepo, that's what lets you run a quick per-package check in a pre-push hook and the full sweep in CI.
Step 3: check PEP 723 scripts against their own dependencies
This is the part I care about most. Say you have a script like this:
# /// script
# requires-python = ">=3.12"
# dependencies = ["requests"]
# ///
import requests
status: int = requests.get("https://example.com")
Run this:
uv check --script fetch.py
uv builds a separate environment from the script's own metadata and checks the script against it, even when it disagrees with the surrounding project. In Chu's test, plain ty check reported unresolved-import for requests because it was looking in the wrong venv. With the integration, it reported the real bug instead. I ran this exact file with uv 0.13.5, which pulled ty 0.0.92, and got the same thing, exit code 1:
error[invalid-assignment]: Object of type `Response` is not assignable to `int`
--> fetch.py:7:15
uv check on its own doesn't go looking for scripts, though. Chu had to name each one with --script. If you want ty to find and check the project's scripts in one pass, the blog gives an env var:
TY_UV=scripts ty check
That setting is opt-in for a good reason. Astral's explanation: "As dependency installation can require execution of third-party Python code, automatic environment setup is currently opt-in." The same applies to uv check itself, so running uv check on a repo you just cloned is not a read-only operation. Treat it like pip install.
Step 4: ty in VS Code with the uv setting
Install the ty extension, make sure uv is on your PATH, and add this to settings.json:
{
"ty.experimental.useUv": "on"
}
With that set, ty runs uv in the background so completions, hover and Go to Definition inside a script use the script's declared requirements and not your project venv. If you write a lot of throwaway uv run scripts, this alone makes the integration worth trying.
Step 5: the ty pre-commit hook
The ty-pre-commit hook now runs uv check under the hood, and the rev tracks the ty version:
repos:
- repo: https://github.com/astral-sh/ty-pre-commit
rev: v0.0.92 # ty version
hooks:
- id: ty
args: [--isolated]
I'd add --isolated right away. Without it, the hook can create or update your uv.lock and .venv during a commit, which is the kind of side effect that eventually costs you an afternoon. The README also suggests [--isolated, --no-python-downloads, --no-cache] if you want more idempotent runs.
Two other gotchas from the README:
- The hook always checks the whole project. Don't set pass_filenames: true, because the hook errors if it receives filenames.
- It doesn't work on pre-commit.ci, which blocks network access. Add ci: skip: [ty] there and run the check in your own CI.
Step 6: uv check in GitHub Actions
The ty-pre-commit README uses astral-sh/setup-uv@v10.3.2. Here's a minimal GitHub Actions job built on that:
typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7.0.1
- uses: astral-sh/setup-uv@v10.3.2
- run: uv check --locked --all-packages
--locked makes the job fail if uv.lock is out of date, so CI can't silently re-resolve and check against different dependencies than the ones you committed.
The catch: uv check only pins ty if you add it
The announcement says uv check "automatically uses the ty version recorded in your project's lockfile," so laptops and CI agree. That only holds once ty is actually in your lockfile.
According to the --ty-version docs, the exact version from uv.lock is used "when ty is a project dependency or a dependency in the project's dev group." If it isn't, uv uses a constrained range like >=0.0,<0.1. ty is at 0.0.9x and ships often, so in that range your laptop and your CI runner can end up on different ty builds, which is exactly the drift the feature is supposed to prevent.
Chu checked this: after uv add --dev "ty==0.0.80", uv check -v used 0.0.80 even though 0.0.91 was out. So the fix is one command:
uv add --dev ty
I did this on a fresh uv init project and uv check -v logged Requirement already installed: ty==0.0.92, the version now in the lockfile.
Do this before you add uv check to CI. I'd argue it should be the default, or at least come with a loud warning.
Should ty replace mypy or Pyright yet?
Not yet, and Astral's post doesn't claim it should. The integration is experimental, ty is still on 0.0.x, and Astral says it is "continuing toward ty's stable release." ty's docs claim it's 10x to 100x faster than mypy and Pyright. I believe the speed claim. What I don't know yet is how many of your existing # type: ignore comments and plugin-dependent patterns (Django, SQLAlchemy, pydantic mypy plugins) will survive the switch.
What I'm doing for now:
| Situation | My call |
|---|---|
| PEP 723 scripts, one-off tools | Use uv check --script now. mypy never handled these well. |
| New project, no mypy plugins | Run uv check in CI next to your current checker for a few weeks |
| Large codebase on mypy plugins | Keep mypy. Try ty in the editor only. |
| Monorepo on uv workspaces | Trial --all-packages in a non-blocking CI job |
Running it next to your current checker costs you about a minute of CI setup. Dropping your current checker for a 0.0.x preview is a bet I'm not making on a production codebase.
So where are you on this? Would you replace mypy or pyright with ty today, or wait until it's out of preview? If you've already switched, tell me which false positives made you want to switch back.
Sources
- Bringing uv and ty together, Astral blog, Oct 13, 2026
- uv CLI reference: uv check
- astral-sh/ty-pre-commit README
- ty documentation
- Frank Chu: Astral wired ty into uv. I ran uv check on a project with four deliberate errors.
- Lobsters discussion
1 reaction · 1 comment
AI Agents Are Quietly Being Rewritten in Rust
OpenAI, Block, and Perplexity all rebuilt key parts of their AI stack in Rust. In this video I break down why the layer around the model (agents, sandboxes, and tooling) is moving to Rust, and the one catch most people skip.
I’m a fresh grad learning Rust and harness engineering in public, so every claim here comes from sources I checked, linked below.
Chapters
0:00 Elon’s Larp
00:36 Codex CLI: TypeScript to Rust
01:46 Goose: Python to Rust
02:22 Sandboxes: Firecracker and Perplexity SPACE
03:14 uv, Ruff, and OpenAI buying Astral
03:50 Hugging Face tokenizers and Candle
04:13 The catch
04:45 Advance
Sources
Elon post : x.com
openai/codex
block/builderbot
perplexityai/SPACE
x.com
codex#1174
news.ycombinator.com
reddit.com
codex#1174
news.ycombinator.com
reddit.com
github.com/aaif-goose/goose/blob/main/crates/goos…
goose-docs.ai
github.com/aaif-goose/goose/blob/main/crates/goos…
firecracker-microvm.github.io
x.com
anthropics/claude-code
reddit.com
huggingface.co
huggingface/candle
astral-sh/uv
astral.sh
github.com/perplexityai/SPACE/tree/main/crates/ap…
firecracker-microvm/firecracker
github.com/aaif-goose/goose/tree/main
Follow along
Rust playlist: youtube.com
Building Harness playlist: youtube.com
Portfolio: vkgeed.in
X post for this video: x.com
#rust #aiengineering #softwareengineering
2 likes · 1,204 views
Mentions
uvの--lockedと--frozenを検証する:CIの同期成功は何を保証するか uv sync --frozenが成功しても、pyproject.tomlへ追加した依存が入っているとは限りません。 小さなプロジェクトでlockfileの更新漏れを作ったところ、--lockedはエラーで止まり、--frozenは成功しました。ただし後者では、新しく追加したidnaをimportできる状態になっていませんでした。 この記事では、この差を再現し、CI(変更のたびにテストなどを実行する仕組み)で何を検証したいかから指定を選びます。実測環境はLinux、uv 0.11.19、Python 3.12.3です。GitHub Actions自体は実行していません。 lockfileが一致していない状態を作る 既存プロジェクトを壊さないよう、空の検証用ディレクトリで行います。uvと、次の条件を満たすPythonが使えることが前提です。 最初のpyproject.tomlは次の内容です。ビルド設定を持たない小さな検証用プロジェクトで、アプリの配布は行いません。 [project] name = "uv-ci-example" version = "0.1.0" requires-python = ">=3.12,<3.13" dependencies = ["packaging>=24,<26"] [dependency-groups] dev = ["pytest>=8,<9"] 比較対象のPython系統をそろえてから、最初のlockを作る uv python pin 3.12 uv lock uv sync --locked ここではpyproject.tomlとuv.lockが整合しています。lockfileは、解決済みの依存関係を記録したファイルです。pyproject.tomlが求める条件と、実際に使う解決結果を別々に扱えるようになります。uvのプロジェクト構成 続いて、pyproject.tomlのdependencies行だけを次へ変更します。 lock更新漏れを再現するため、この段階ではuv addを使わない dependencies = ["packaging>=24,<26", "idna==3.10"] この行は既存の[project]内にある行を置き換えるものです。別の場所へ追記しないでください。通常の依存追加にはuv addを使えますが、今回は意図的にuv.lockを更新しない状態を作っています。uvの依存関係管理 --lockedでは更新漏れを検出できた 設定とlockの不整合を検出できるか確認する uv sync --locked 実測では終了コード1になり、lockfileの更新が必要なのに--lockedが指定されている、というエラーになりました。uv.lockの内容は変更されていません。 これは想定した失敗です。CIに「コミットされた依存設定を、そのlockfileで扱えるか」を検証させたいなら、この段階で止まることに意味があります。 --frozenは成功したが、追加依存は入らなかった 同じ状態のまま、今度は次を実行しました。 不整合な設定を保ったまま、既存lockを使った場合を比較する uv sync --frozen 通常のuv runによる自動更新を避け、未導入の状態を調べる uv run --frozen python -c "import importlib.util; assert importlib.util.find_spec('idna') is None" 両コマンドとも終了コード0でした。2つ目のコマンドが成功したことは、この環境でidnaが見つからなかったことを意味します。uv.lockも変更されていません。 確認時にuv runへ--frozenを付けたのは、観測中にlockや環境が自動更新されるのを避けるためです。通常のuv runには、コマンドの起動前に必要なlockと同期を行う動作があります。uvのlockと同期 2つの指定は、確認する条件が違う 図:公式仕様と本記事の検証を基に独自作成。GitHub上の実行画面ではありません。 操作 今回の不整合への動作 成功から読み取れること uv sync --locked 更新が必要なので停止 成功した場合、uvの判定でlockが現在の設定と整合している uv sync --frozen 整合性確認を省き、古いlockで同期 選ばれたlockと同期対象のグループで環境を作れた。現在の設定との整合性は別途確認が必要 uv lockの後にuv sync --locked lockを更新してから同期 更新した解決結果を使って環境を作れる --frozenは「より厳しい固定」という意味ではなく、lockfileの最新性確認を省く指定です。仕様はLocking and syncingに記載されています。 また、--lockedもファイルの文字列が完全一致するかを検査するものではありません。たとえば依存の条件を変えても、既存lockが引き続き条件を満たす場合があります。新しいパッケージ版が公開されたことだけで、lockが不整合になるわけでもありません。 このため、通常のCIでは--lockedを出発点にし、別工程で整合性を保証しているなどの理由がある場合に--frozenを選ぶ、という整理ができます。 更新する工程と、検証する工程を分ける 先ほどの検証用プロジェクトでは、次の操作で不整合を解消できます。 依存変更をlockへ反映し、差分をレビューできる状態にする uv lock uv sync --locked 更新後には追加した依存が見つかることを確認する uv run --locked python -c "import importlib.util; assert importlib.util.find_spec('idna') is not None" CIへ渡すときは、pyproject.tomlとuv.lockの両方をGitで管理します。通常のテスト実行中にlockを作り直すより、依存を変更する作業で更新し、その差分を確認してからCIへ渡す方が、何をテストしたかを追いやすくなります。 pytestをdevグループに登録したプロジェクトなら、uvとPythonの準備後のテスト部分は次のようになります。これはjobs.<job_id>.steps内の断片です。 - name: Sync dependencies CI内の暗黙のlock更新で、更新漏れが隠れるのを防ぐ run: uv sync --locked - name: Run tests テスト起動時にも同じ整合性条件を保つ run: uv run --locked pytest -q uv runにも--lockedを付けることで、実行直前の自動更新に頼らず検証します。tests/にはプロジェクトのテストを用意してください。上の依存設定と同期だけでは、テストケースは生成されません。uvのGitHub Actions連携 lockfileだけで実行環境全体が固定されるわけではない 図:公式仕様と本記事の検証を基に独自作成。GitHub上の実行画面ではありません。 ローカル検証では、pytest 8.4.2とpackaging 25.0を導入し、バージョンの順序を比較するテスト3件を実行しました。検証用の.venvを削除して再同期した後も、同じ3件が成功しました。依存追加後にlockを更新した後も成功しています。 ただし、これはGitHubのrunner(ジョブを実行するマシン)でも同じ挙動になることをすべて確認した結果ではありません。 対象 そろえる方法 注意点 依存関係 uv.lockを共有し、--lockedで同期 OSやPython条件により導入対象が変わり得る uv本体 setup-uvのversion入力などで指定 Actionの版だけではuv本体まで固定されない Python CIと手元で同じ版を選択 3.12指定ではパッチ版まで一致するとは限らない OS 対象runnerを選ぶ 同じOSラベルでもイメージ内部は更新される Pythonの選択とuv本体の導入方法は、uvのPythonバージョン管理とsetup-uvの入力設定を参照してください。 キャッシュヒットでもsyncは必要 キャッシュは取得・ビルド済みの成果物を再利用する仕組みです。今回必要なパッケージを決めるlockfileや、その内容から環境を作る同期処理の代わりにはなりません。uvのキャッシュ キャッシュが復元できてもuv sync --lockedは実行し、今回の環境を整えます。逆にキャッシュがない初回でも、必要なパッケージを取得できればテストまで進める構成にします。 私は、CIでの再現性は「固定するファイルを増やす」だけでなく、どの不整合をエラーにするかを決めることが大事だと考えています。今回の例では、--frozenで同期できたことより、--lockedが更新漏れを検出したことの方が、依存変更をレビューする目的に合っていました。 公式資料の確認日は2026年9月11日です。ローカルでの同期・不整合検出・テストを確認し、GitHub Actionsのイベント発火、Actionの実行、キャッシュ復元と速度は未検証として区別しています。 uvのプロジェクト管理へ移るところから確認したい場合は、uvとpip・venvの違いと移行手順も参照してください。 GitHub Actionsへ導入するためのworkflow全体と、Python・uvの固定、キャッシュ、サブディレクトリの設定は、uvをGitHub Actionsで使う方法にまとめています。
OpenAI, Hugging Face, Google: Why They All Reach for Rust OpenAI rewrote Codex CLI in Rust. Hugging Face's tokenizers, safetensors, uv and Ruff all run on Rust. Why does a Python world keep reaching for it? The problem Rust solves (speed or safety), where it already runs in AI, what it honestly costs, and the plan for this series: Rust from zero, one picture at a time. Chapters 0:00 AI keeps reaching for Rust 0:46 The problem: speed or safety 1:34 What Rust does differently 2:03 Does it work? Android's numbers 2:40 Where Rust runs in AI today 4:04 Is Rust replacing Python? 4:29 The honest cost 4:59 The plan: two playlists 5:28 What would you build? Next: Episode 1: Your first Rust program The whole series, in order: Learn Rust from Zero (Beginners) · Rust You Can See (playlist) Sources - OpenAI Codex CLI rewrite: codex#1174 - Hugging Face tokenizers: huggingface/tokenizers - safetensors joins the PyTorch Foundation: pytorch.org - uv: astral-sh/uv · Ruff: astral-sh/ruff - Astral agrees to join OpenAI: astral.sh - Microsoft, ~70% of CVEs are memory safety: microsoft.com - Chromium memory safety: chromium.org - Android memory safety: security.googleblog.com · blog.google - The Case for Memory Safe Roadmaps (2023): cisa.gov - Linux 6.1 (Rust support): kernelnewbies.org - Stack Overflow 2025 survey: survey.stackoverflow.co - GitHub Octoverse 2025: github.blog - TypeScript's native port in Go: devblogs.microsoft.com - Rust compiler performance survey 2025: blog.rust-lang.org - Pydantic core: pydantic/pydantic-core · Polars: pola.rs Ferris the crab is the Rust community's mascot (public domain, rustacean.net). Rust You Can See is an independent series, not affiliated with or endorsed by the Rust Project or the Rust Foundation. Rust is a trademark of the Rust Foundation. Narration: AI-generated voices. #rust #learnrust #programming [es] Por qué la IA se está pasando a Rust [fr] Pourquoi l'IA se tourne vers Rust [hi] AI अब Rust पर क्यों शिफ्ट हो रहा है? [ja] なぜAIはRustへ移行しているのか [ko] AI가 Rust로 옮겨가는 이유 [pt-BR] Por que a IA está migrando para Rust
@thsottiaux Yes ruff#29852
Tinyworldformer corre en un Pico 2W de $6 con 520 KB de RAM Un microcontrolador de 6 dólares acaba de ejecutar, en tiempo real, un modelo de mundo comprimido que inventa videojuegos cuadro por cuadro. El proyecto tinyworldformer corre dentro de 520 KB de RAM en una Raspberry Pi Pico 2W, sin GPU, sin nube y sin conexión a internet. Su autor lo logró separando el trabajo en dos redes neuronales por fotograma. Una genera el siguiente cuadro del juego, la otra decide qué botón presionar, y ambas corren a la vez sobre el mismo chip. TL;DR - Int8 y pesos compartidos reducen el generador de frames a entre 26.000 y 131.000 parámetros según el juego.- Un bloque transformer aplicado de 1 a 4 veces sustituye a una pila de capas distintas y ahorra memoria.- La red actora, separada del generador, pesa solo entre 9.000 y 16.000 parámetros en float32.- El RP2350 reparte el trabajo: el núcleo 1 corre ambas redes, el núcleo 0 atiende USB y pantalla.- El repositorio SheepSeb/tinyworldformer deja jugar los cinco juegos reales desde la terminal con uv. ¿Qué es un modelo de mundo comprimido? Un modelo de mundo comprimido es una red neuronal generativa reducida en tamaño y precisión para correr sin GPU: tinyworldformer la implementa como un transformer en bucle cuantizado a 8 bits que predice el siguiente fotograma de un videojuego y cabe en los 520 KB de RAM de un microcontrolador de 6 dólares. La idea de partida de su autor fue simple. Los transformers en bucle reutilizan el mismo bloque de pesos varias veces en lugar de apilar capas distintas, así que ocupan mucha menos memoria por diseño. Si ese ahorro era suficiente, un modelo generativo completo podía caber en un chip de bolsillo. Por qué importa La mayoría de los modelos generativos de video o de juegos dependen de una GPU con varios gigabytes de memoria. Tinyworldformer invierte esa ecuación: corre en un chip pensado para termostatos y drones de juguete. Eso importa para el campo conocido como edge computing, donde el objetivo es mover la inferencia al dispositivo en lugar de depender de un servidor remoto. Un modelo que corre en el borde no necesita conexión a internet, no paga latencia de red y no expone datos a un servidor externo. Acá el beneficio es además una prueba de concepto. Si una red generativa cabe en 520 KB, la pregunta deja de ser si el edge AI puede generar contenido y pasa a ser cuánto contenido puede generar con ese presupuesto de memoria. El ángulo de costo pesa tanto como el técnico. Una Raspberry Pi Pico 2W cuesta una fracción de lo que cuesta cualquier GPU capaz de correr un transformer completo, y consume órdenes de magnitud menos energía porque no tiene memoria de video ni refrigeración activa. Para proyectos de hobby, educación o investigación en TinyML, esa diferencia de costo decide si un experimento se hace o no. Cómo funciona tinyworldformer por dentro Tinyworldformer separa el problema en dos redes con trabajos distintos. La primera, el generador de frames, recibe el cuadro actual y la acción del jugador y predice el cuadro siguiente junto con la recompensa. La segunda, la red actora, solo mira el cuadro y decide qué acción tomar. Ninguna de las dos ve jamás el juego real una vez que arranca la sesión: el generador solo recibe acciones de la actora, y la actora solo ve cuadros inventados por el generador. sequenceDiagram participant Actor as Red actora participant Generador as Generador de frames Actor->>Generador: envia accion Generador-->>Actor: entrega frame generado y recompensa Note over Actor,Generador: el generador nunca ve el juego real Tokenización en parches Antes de entrar al transformer, cada cuadro se recorta en parches cuadrados: 2x2 celdas en Breakout, 4x4 en Doom-lite, Flappy Bird y Pong, 6x6 en Pac-Man lite. Eso da entre 36 y 80 tokens por juego según el repositorio. Cada token suma un vector aprendido por celda, con una tabla distinta según la posición dentro del parche para no perder el orden, más un vector de posición y un vector de la acción tomada. Un ejemplo simplificado en Python muestra la misma idea con un cuadro diminuto de 4x4 dividido en parches de 2x2: import numpy as np frame = np.array([ [1, 1, 2, 2], [1, 1, 2, 2], [3, 3, 4, 4], [3, 3, 4, 4], ]) def a_parches(frame, parche=2): h, w = frame.shape tokens = [] for i in range(0, h, parche): for j in range(0, w, parche): tokens.append(frame[i:i+parche, j:j+parche].flatten()) return np.array(tokens) print(a_parches(frame)) La salida literal es una matriz de 4 tokens, uno por cada región homogénea del cuadro: [[1 1 1 1] [2 2 2 2] [3 3 3 3] [4 4 4 4]] El transformer en bucle En lugar de apilar, por ejemplo, ocho bloques transformer distintos, tinyworldformer usa un único bloque (atención más una red feedforward con ReLU) y lo aplica entre 1 y 4 veces seguidas, sumando la entrada original antes de cada pasada. El resultado de cada pasada se entrena contra el cuadro siguiente real, así que el número de pasadas en tiempo de ejecución es un control directo entre velocidad y precisión. En el Pico 2W, para mantener una tasa de cuadros razonable, el proyecto usa dos pasadas. flowchart TD A["Frame t + accion"] --> B["Tokenizar en parches"] B --> C["Bloque transformer (pesos compartidos)"] C --> D{"Repetir de 1 a 4 veces"} D -->|"otra pasada"| C D -->|"pasada final"| E["Frame t+1 y recompensa"] Cuantización y reparto entre núcleos El generador de frames se cuantiza a int8, mientras que la red actora se queda en float32 porque ya es pequeña de por sí, entre 9.000 y 16.000 parámetros, y la precisión ahí importa más para decidir bien la acción. El RP2350 del Pico 2W tiene dos núcleos: el núcleo 1 corre el generador y la actora, el núcleo 0 se encarga del USB y de la pantalla, según documenta el repositorio. Esa separación entre generador y actor permite optimizar cada red por separado. El generador, la parte pesada, recibe toda la cuantización, mientras que la actora, ya liviana, se queda intacta en float32. El RP2350 integra FPU, pieza clave para ejecutar redes cuantizadas. flowchart TD A["RP2350 dual-core"] --> B["Nucleo 0: USB y pantalla"] A --> C["Nucleo 1: inferencia"] subgraph Inferencia["Nucleo de inferencia"] C --> D["Generador de frames int8"] C --> E["Red actora float32"] end Ejemplos prácticos y cómo empezar El repositorio incluye cinco juegos reales escritos en unas pocas líneas de numpy, lo que le permite a su autor comparar cada frame generado contra la física real del juego. La siguiente tabla resume el costo de memoria y cómputo de cada uno, con datos publicados en el repositorio de tinyworldformer: JuegoTamaño de frameParámetrosMACs por frameFrames exactosBreakout20x1626k4.3M99.99%Doom-lite32x3255k4.2M83.6%Flappy Bird24x2446k2.0M100%Pong20x3246k2.3M99.45%Pac-Man lite48x48131k8.2M86.4% La columna de frames exactos mide el porcentaje de transiciones donde cada celda del cuadro predicho coincide con el cuadro real. Doom-lite tiene el número más bajo, 83.6%, pero no porque juegue mal: su vista en primera persona tiene 768 celdas, y un solo píxel de sombra mal pintado ya marca todo el cuadro como incorrecto en esta métrica. Cómo probarlo en tu máquina El proyecto usa uv como gestor de paquetes de Python, así que no hace falta instalar dependencias a mano una por una. En Linux o macOS: curl -LsSf https://astral.sh/uv/install.sh | sh git clone https://github.com/SheepSeb/tinyworldformer cd tinyworldformer uv run python -m tinyworldformer.games.play --game pacman En Windows, el único paso que cambia es la instalación de uv, desde PowerShell: powershell -c "irm https://astral.sh/uv/install.ps1 | iex", y luego los mismos comandos de git clone y uv run. El comando play acepta también breakout, doomlite, flappy o pong en lugar de pacman. No hay salida de texto que mostrar: uv descarga las dependencias declaradas en el pyproject.toml y abre una ventana gráfica con el juego real corriendo en numpy, el mismo que el generador de frames aprendió a imitar. > 💡 Tip: correr primero el juego real con play antes de buscar los pesos entrenados ayuda a entender qué está tratando de imitar el generador cuantizado, celda por celda. Casos de uso reales Tinyworldformer no apunta a reemplazar un motor de videojuegos. Su valor está en lo que demuestra: un modelo generativo entrenado sobre partidas grabadas puede, cuantizado y comprimido, correr en el mismo chip que hoy maneja sensores de temperatura o drones de juguete baratos. El caso de uso inmediato es educativo y de investigación en TinyML, pero la receta (tokenizar en parches, compartir pesos entre pasadas, cuantizar solo la parte más pesada) es trasladable a otros generadores pequeños, como un simulador de sensor para probar un controlador embebido sin hardware real conectado. El repositorio también suma un agente de refuerzo por streaming que aprende a jugar dentro del sueño generado por el propio modelo, en lugar de solo repetir una política ya entrenada. Cualquier botón del dispositivo le devuelve el control al usuario humano, así que la misma placa sirve para ver a la IA jugar sola o para jugar uno mismo dentro del mundo que ella inventa. Breakout necesita solo 26.000 parámetros; Pac-Man lite necesita 131.000. Errores comunes y buenas prácticas - Confundir precisión de píxel con jugabilidad. Un 83.6% de frames exactos suena mal hasta que se entiende la métrica: un solo píxel de sombra distinto ya cuenta como fallo total del cuadro, aunque el estado del juego (posición del enemigo, vida, puntaje) siga siendo correcto.- Cuantizar todo por igual. Aplicar int8 a la red actora, que ya tiene menos de 16.000 parámetros, aportaría poco ahorro de memoria y arriesgaría la precisión de la política. La cuantización rinde donde el modelo es grande, no donde ya es pequeño.- Elegir mal el número de pasadas del bucle. Una sola pasada del transformer es más rápida pero deja artefactos visibles, un enemigo que no debería estar ahí, por ejemplo. Cuatro pasadas corrigen casi todo el error pero cuestan más tiempo de cómputo por cuadro. Dos pasadas fue el punto que eligió el proyecto para el Pico 2W.- Verificar contra la física real, no solo mirar el video generado. Tener la versión real del juego en numpy, como hace este repositorio, es lo que permite medir el error cuadro por cuadro en lugar de confiar en que se vea bien. Comparativa con alternativas para generar contenido con IA EnfoqueCuándo usarloVentajaLimitaciónTransformer completo en GPU o nubeCuando la latencia de red no importa y hay presupuesto de cómputoMáxima fidelidad del frame generadoDepende de conexión e infraestructura externaModelo de mundo comprimido en microcontrolador (tinyworldformer)Dispositivos aislados, sin GPU, con RAM y flash muy limitadosCorre offline, sin latencia de red, consumo mínimoSolo viable en juegos o dominios muy pequeñosDistillation genérica a modelos pequeños (TinyML clásico)Tareas de clasificación o detección simples en sensoresHerramientas y runtimes madurosNo pensado para generar secuencias completas de frames La fila intermedia describe a tinyworldformer. No busca competir en fidelidad visual con un generador de video entrenado en GPU; busca que el juego siga siendo jugable dentro de un presupuesto de memoria minúsculo. Profundizando: por qué el bucle ahorra memoria y dónde se nota el límite La razón de fondo por la que un transformer en bucle pesa menos es aritmética simple: un transformer tradicional de N capas guarda N juegos de pesos distintos, mientras que el bucle guarda un solo juego de pesos y lo reusa N veces. El costo que se paga a cambio es tiempo de cómputo, cada pasada adicional cuesta los mismos multiplica-acumula que la anterior, en lugar de memoria, y en un microcontrolador la memoria suele ser el recurso más escaso de los dos. La cuantización int8 agrega un segundo ahorro, independiente del anterior: cada peso pasa de ocupar 4 bytes en float32 a ocupar 1 byte, a costa de redondear cada valor a uno de 256 niveles posibles. El siguiente ejemplo en Python muestra ese redondeo con cuatro pesos cualquiera: import numpy as np pesos = np.array([0.42, -0.87, 1.35, -1.90], dtype=np.float32) escala = np.max(np.abs(pesos)) / 127 cuantizados = np.round(pesos / escala).astype(np.int8) reconstruidos = cuantizados.astype(np.float32) * escala print(cuantizados) print(np.round(reconstruidos, 4)) La salida literal es: [ 28 -58 90 -127] [ 0.4189 -0.8678 1.3465 -1.9 ] El peso original de 1.90 se reconstruye exacto porque definió la escala; los otros tres cargan un pequeño error de redondeo. Ese error, multiplicado por miles de pesos y varias pasadas del bucle, ayuda a explicar por qué Pac-Man lite, el juego más complejo con 131.000 parámetros, tiene un porcentaje de frames exactos menor que Flappy Bird. No hay una forma directa de verificar desde afuera, sin acceso al checkpoint, cuánto de ese error viene de la cuantización y cuánto del tamaño del juego; lo más cercano que ofrece el propio repositorio es comparar el porcentaje de frames exactos por juego de la tabla anterior. El FPU del RP2350 importa en este punto. Sin una unidad de punto flotante en hardware, la dequantización, volver de int8 a valores reales antes de cada operación de atención, sería mucho más lenta, porque el chip tendría que emular esas operaciones en software. > 💭 Clave: el ahorro de memoria del bucle y el ahorro de la cuantización son independientes entre sí; tinyworldformer los combina, pero cada uno podría usarse por separado en otro proyecto. 📖 Resumen en Telegram: Ver resumen Tu próximo paso: cloná el repositorio, corré uv run python -m tinyworldformer.games.play --game breakout y leé el archivo de ese juego dentro de src/tinyworldformer/games/ para ver cuántas líneas de numpy hacen falta para una física jugable completa. Preguntas frecuentes ¿Qué microcontrolador corre el modelo de mundo comprimido de tinyworldformer? Una Raspberry Pi Pico 2W, construida sobre el chip RP2350, que tiene dos núcleos y una unidad de punto flotante. El núcleo 1 ejecuta el generador de frames y la red actora; el núcleo 0 atiende USB y la pantalla. ¿Cuántos parámetros tiene el transformer en bucle de cada juego? Entre 26.000 y 131.000, según la complejidad del juego: Breakout es el más liviano y Pac-Man lite el más pesado, de acuerdo con la tabla publicada en el repositorio. ¿Hace falta GPU para entrenar tinyworldformer antes de cuantizarlo? El repositorio no detalla el hardware exacto de entrenamiento, pero el generador de frames se entrena sobre partidas grabadas del juego real, un proceso que normalmente se hace fuera del microcontrolador y antes de cuantizar los pesos para desplegarlos en el Pico 2W. ¿Qué diferencia a la red actora de la IA embebida en microcontroladores que genera los frames? La red actora es una MLP mucho más chica, entre 9.000 y 16.000 parámetros, que se queda en float32 porque su tarea, decidir una acción a partir de un frame, tolera peor el error de cuantización que generar el frame en sí. ¿Se puede correr tinyworldformer en un microcontrolador distinto al Pico 2W? El repositorio está construido específicamente para el RP2350 del Pico 2W, incluyendo una carpeta en Rust para el firmware del dispositivo. Portarlo a otro chip exigiría al menos una FPU y memoria suficiente para los buffers de atención, pero el propio proyecto no documenta otros objetivos probados. Referencias - GitHub: SheepSeb/tinyworldformer: repositorio original con el código, los juegos en numpy y los datos de tamaño y precisión de cada modelo.- Raspberry Pi: fabricante oficial de la Raspberry Pi Pico 2W y el chip RP2350 usado en el proyecto.- Wikipedia: Edge computing: contexto sobre mover la inferencia de IA al dispositivo en lugar de a un servidor remoto.- Wikipedia: Quantization: fundamento matemático de la cuantización usada para pasar los pesos de float32 a int8. 📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.
It depends who you trust :slight_smile: Astral/OpenAI build binaries at Python Build Standalone: astral-sh/python-build-standalone These are used by projects such as uv, Hatch and PDM.
> why this exists docs.basedpyright.com > The "type server protocol" is a desperate attempt from microsoft to prevent pylance from becoming obsolete by outsourcing its type checking to other language servers like basedpyright, ty or pyrefly -- while continuing to keep certain language server features exclusive to pylance. > This protocol benefits nobody except microsoft. It adds needless complexity to any language server that chooses to support it. Basedpyright does not support it and strongly advises other language servers to avoid supporting it as well. > For more info see here pylance-release#7180 and here ty#1190
DetachHead (maintainer of basedpyright) has criticized the TSP before: - docs.basedpyright.com - pylance-release#7180 Ty (the type checker maintained by astral) however will apparently support the TSP: ruff#23432
Rust Didn't Win Because It's Fast GitHub rewrote Copilot's runtime in Rust. OpenAI's Codex is now almost all Rust. Bun, the runtime Claude Code ships on, moved 535,496 lines of Zig to Rust in 11 days. But it isn't about speed: C has been fast for half a century. We fly inside a real laptop, down to the CPU die and the memory cells, to show what Rust actually changed, and why AI coding agents love it. 0:00 Everyone is rewriting in Rust 0:49 This is Sidequest Explained 1:00 Inside the machine: instructions, bytes, stack and heap 1:53 Way one: freeing memory by hand (C and C++) 2:23 An elevator crash started Rust 2:40 Way two: the garbage collector (Discord's spikes) 3:12 Way three: ownership 3:36 Checked before it runs, and Android's results 4:07 Close to the metal: 28 bytes vs 8 4:21 Copilot: 5.25 s to 292 ms 4:41 Why AI agents love the Rust compiler 5:11 Is Python dead? What it means for you Sources GitHub Blog, migrating the Copilot runtime to Rust (Sep 2026): github.blog Bun, Rewriting Bun in Rust (Jul 2026): bun.sh OpenAI Codex repository: openai/codex Codex native rewrite discussion: codex#1174 Grok Build repository: xai-org/grok-build Dennis Ritchie, The Development of the C Language: bell-labs.com Microsoft MSRC, 70% of security bugs are memory safety (2019): microsoft.com Chromium memory safety: chromium.org MIT Technology Review, Rust's origin (2023): technologyreview.com Rust 1.0 announcement: blog.rust-lang.org Discord, Why Discord is switching from Go to Rust (2020): discord.com The Rust Book, ownership and borrowing: doc.rust-lang.org Google, memory-safe languages in Android 13 (2022): security.googleblog.com Google, Rust in Android (Nov 2025): blog.google Python sys.getsizeof / CPython ints: docs.python.org Hugging Face tokenizers: huggingface/tokenizers OpenAI tiktoken: openai/tiktoken pydantic-core: pydantic/pydantic-core uv by Astral: astral-sh/uv Numbers are the sources' own. The Copilot timings are client + session + one-turn overhead in the opt-in in-process mode, not counting the model or network. Android's 1000× is memory-safety vulnerability density. Code on screen is an illustration, not a run. Credits Die micrographs: Fritzchens Fritz (CC0). Memory-cell micrograph (Micron MT4C1024) and SEM plate (1886VE10): ZeptoBars, CC BY 3.0. Office and hardware photos: Pexels. HDRIs and materials: Poly Haven, ambientCG (CC0). Music: "Lofi Study" by FASSounds (Pixabay). Rust, GitHub, Copilot, OpenAI, Codex, Bun, Claude, xAI, Grok, Microsoft, Chrome, Android, Discord, Python, Hugging Face, Astral, pydantic and other names and logos belong to their owners, used for identification and commentary; Sidequest is not affiliated with any of them. Narration: an AI clone of my own voice. Animation: original, built in three.js. #rust #programming #ai
uv Now Type-Checks Python with ty. How to Set Up uv check (Pin ty First) uv now has a type-check command. uv check syncs your project environment, downloads the ty type checker and runs it, with no config and no separate pip install. It also checks PEP 723 scripts against their own inline dependencies, which is the part that got me: your type checker has probably been checking those scripts against the wrong venv for years, flagging import requests as unresolved or silently using whatever happened to be installed. I've been running it and I like it. The "your laptop and CI use the same ty version" pitch needs a footnote, though, and one command fixes it. I'll go through projects first, then workspaces, scripts, VS Code, pre-commit and GitHub Actions. What uv check actually does Per the announcement from October 13, 2026, uv check prepares the project environment, installs its dependencies and checks the project with ty. You need uv 0.12.3 or later and ty 0.0.76 or later. ty itself gets downloaded the first time you run the command, so you don't install it yourself. It's a preview feature. Astral says so plainly, and if you never run uv check, nothing about your uv workflow changes. The CLI reference describes it as "Run checks on the project," and adds: "Currently, this type checks Python code using ty." There's also a --fix flag to apply safe fixes. Ruff is on the roadmap but not in the command yet. Frank Chu tested this by adding unused import os and import sys: uv check didn't report either of them. So keep your ruff check step for now. Step 1: type-check a project with uv check uv self update # make sure you're on 0.12.3+ uv check That's the whole setup. On the first run in Chu's test (uv 0.13.5, ty 0.0.91, a 2 vCPU VM), uv created .venv, pulled a managed CPython, built the project and downloaded ty, which was 13.5 MiB. The cold run took 5.53s and warm runs took 0.71s. Bare ty check on the same tiny project took 0.09s, so ty barely registers and most of the time goes to uv syncing the environment. The exit codes are what CI expects: 1 when there are diagnostics, 0 when the code is clean. Every run prints an experimental warning. Chu found you can silence it with --preview-features check-command. Step 2: workspaces with --package and --all-packages If you use a uv workspace, the flags work the same way they do in uv sync: uv check --package api # one member: syncs it + its deps, checks only its files uv check --all-packages # every member in the workspace The reference docs say --package syncs the workspace environment with the selected members and their dependencies, and "only files owned by those members are checked." In a monorepo, that's what lets you run a quick per-package check in a pre-push hook and the full sweep in CI. Step 3: check PEP 723 scripts against their own dependencies This is the part I care about most. Say you have a script like this: # /// script # requires-python = ">=3.12" # dependencies = ["requests"] # /// import requests status: int = requests.get("https://example.com") Run this: uv check --script fetch.py uv builds a separate environment from the script's own metadata and checks the script against it, even when it disagrees with the surrounding project. In Chu's test, plain ty check reported unresolved-import for requests because it was looking in the wrong venv. With the integration, it reported the real bug instead. I ran this exact file with uv 0.13.5, which pulled ty 0.0.92, and got the same thing, exit code 1: error[invalid-assignment]: Object of type `Response` is not assignable to `int` --> fetch.py:7:15 uv check on its own doesn't go looking for scripts, though. Chu had to name each one with --script. If you want ty to find and check the project's scripts in one pass, the blog gives an env var: TY_UV=scripts ty check That setting is opt-in for a good reason. Astral's explanation: "As dependency installation can require execution of third-party Python code, automatic environment setup is currently opt-in." The same applies to uv check itself, so running uv check on a repo you just cloned is not a read-only operation. Treat it like pip install. Step 4: ty in VS Code with the uv setting Install the ty extension, make sure uv is on your PATH, and add this to settings.json: { "ty.experimental.useUv": "on" } With that set, ty runs uv in the background so completions, hover and Go to Definition inside a script use the script's declared requirements and not your project venv. If you write a lot of throwaway uv run scripts, this alone makes the integration worth trying. Step 5: the ty pre-commit hook The ty-pre-commit hook now runs uv check under the hood, and the rev tracks the ty version: repos: - repo: https://github.com/astral-sh/ty-pre-commit rev: v0.0.92 # ty version hooks: - id: ty args: [--isolated] I'd add --isolated right away. Without it, the hook can create or update your uv.lock and .venv during a commit, which is the kind of side effect that eventually costs you an afternoon. The README also suggests [--isolated, --no-python-downloads, --no-cache] if you want more idempotent runs. Two other gotchas from the README: - The hook always checks the whole project. Don't set pass_filenames: true, because the hook errors if it receives filenames. - It doesn't work on pre-commit.ci, which blocks network access. Add ci: skip: [ty] there and run the check in your own CI. Step 6: uv check in GitHub Actions The ty-pre-commit README uses astral-sh/setup-uv@v10.3.2. Here's a minimal GitHub Actions job built on that: typecheck: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7.0.1 - uses: astral-sh/setup-uv@v10.3.2 - run: uv check --locked --all-packages --locked makes the job fail if uv.lock is out of date, so CI can't silently re-resolve and check against different dependencies than the ones you committed. The catch: uv check only pins ty if you add it The announcement says uv check "automatically uses the ty version recorded in your project's lockfile," so laptops and CI agree. That only holds once ty is actually in your lockfile. According to the --ty-version docs, the exact version from uv.lock is used "when ty is a project dependency or a dependency in the project's dev group." If it isn't, uv uses a constrained range like >=0.0,<0.1. ty is at 0.0.9x and ships often, so in that range your laptop and your CI runner can end up on different ty builds, which is exactly the drift the feature is supposed to prevent. Chu checked this: after uv add --dev "ty==0.0.80", uv check -v used 0.0.80 even though 0.0.91 was out. So the fix is one command: uv add --dev ty I did this on a fresh uv init project and uv check -v logged Requirement already installed: ty==0.0.92, the version now in the lockfile. Do this before you add uv check to CI. I'd argue it should be the default, or at least come with a loud warning. Should ty replace mypy or Pyright yet? Not yet, and Astral's post doesn't claim it should. The integration is experimental, ty is still on 0.0.x, and Astral says it is "continuing toward ty's stable release." ty's docs claim it's 10x to 100x faster than mypy and Pyright. I believe the speed claim. What I don't know yet is how many of your existing # type: ignore comments and plugin-dependent patterns (Django, SQLAlchemy, pydantic mypy plugins) will survive the switch. What I'm doing for now: | Situation | My call | |---|---| | PEP 723 scripts, one-off tools | Use uv check --script now. mypy never handled these well. | | New project, no mypy plugins | Run uv check in CI next to your current checker for a few weeks | | Large codebase on mypy plugins | Keep mypy. Try ty in the editor only. | | Monorepo on uv workspaces | Trial --all-packages in a non-blocking CI job | Running it next to your current checker costs you about a minute of CI setup. Dropping your current checker for a 0.0.x preview is a bet I'm not making on a production codebase. So where are you on this? Would you replace mypy or pyright with ty today, or wait until it's out of preview? If you've already switched, tell me which false positives made you want to switch back. Sources - Bringing uv and ty together, Astral blog, Oct 13, 2026 - uv CLI reference: uv check - astral-sh/ty-pre-commit README - ty documentation - Frank Chu: Astral wired ty into uv. I ran uv check on a project with four deliberate errors. - Lobsters discussion
AI Agents Are Quietly Being Rewritten in Rust OpenAI, Block, and Perplexity all rebuilt key parts of their AI stack in Rust. In this video I break down why the layer around the model (agents, sandboxes, and tooling) is moving to Rust, and the one catch most people skip. I’m a fresh grad learning Rust and harness engineering in public, so every claim here comes from sources I checked, linked below. Chapters 0:00 Elon’s Larp 00:36 Codex CLI: TypeScript to Rust 01:46 Goose: Python to Rust 02:22 Sandboxes: Firecracker and Perplexity SPACE 03:14 uv, Ruff, and OpenAI buying Astral 03:50 Hugging Face tokenizers and Candle 04:13 The catch 04:45 Advance Sources Elon post : x.com openai/codex block/builderbot perplexityai/SPACE x.com codex#1174 news.ycombinator.com reddit.com codex#1174 news.ycombinator.com reddit.com github.com/aaif-goose/goose/blob/main/crates/goos… goose-docs.ai github.com/aaif-goose/goose/blob/main/crates/goos… firecracker-microvm.github.io x.com anthropics/claude-code reddit.com huggingface.co huggingface/candle astral-sh/uv astral.sh github.com/perplexityai/SPACE/tree/main/crates/ap… firecracker-microvm/firecracker github.com/aaif-goose/goose/tree/main Follow along Rust playlist: youtube.com Building Harness playlist: youtube.com Portfolio: vkgeed.in X post for this video: x.com #rust #aiengineering #softwareengineering