VoltageInputMcp
VoltageInputMcp
Un servidor MCP que permite a un modelo de frontera manejar un ordenador a velocidad de entrada en lugar de a velocidad de llamada de herramienta.
El problema
Las herramientas de uso de ordenador hacen un viaje de ida y vuelta a un modelo remoto para cada acción. Captura de pantalla arriba, decisión abajo, un clic. Eso está bien para rellenar un formulario y es inútil para cualquier cosa que necesite una secuencia de entradas entregadas rápidamente — jugar a un juego, trabajar con un diálogo modal, manejar una línea de tiempo, cualquier interfaz donde la tercera entrada dependa de que las dos primeras ya hayan llegado. El cuello de botella no es la inteligencia del modelo. Es que esa inteligencia está a 800 ms de distancia y las entradas necesitan estar a 8 ms de distancia.
La forma de la respuesta
Separar decidir de hacer, y poner el hacer en la misma máquina que el teclado.
┌─────────────────────────────────────────────────────────────────┐
│ Layer 1 — the orchestrator (Claude, or any MCP client) │
│ Writes a Playbook: states, what to look for, what is allowed, │
│ when to move on. Thinks once, up front. Watches and corrects. │
└───────────────────────────┬─────────────────────────────────────┘
│ MCP
┌───────────────────────────▼─────────────────────────────────────┐
│ Layer 2 — two small local models, on your GPU │
│ │
│ vision (Qwen2.5-VL-3B) "of these specific things, │
│ which are on screen, and where?" │
│ actuator (Qwen3-1.7B) "given that, which inputs?" │
│ │
│ Neither plans. Both answer one closed question per cycle. │
└───────────────────────────┬─────────────────────────────────────┘
│
┌───────────────────────────▼─────────────────────────────────────┐
│ safety governor → /dev/uinput → the actual desktop │
└─────────────────────────────────────────────────────────────────┘El orquestador es el cerebro. Los modelos pequeños son los brazos. Los brazos no son inteligentes y nunca se les pide que lo sean.
De dónde viene realmente la velocidad
No de que los modelos pequeños sean rápidos — un VLM de 3B sigue costando ~300 ms. Viene de cuatro cosas, en orden descendente de impacto:
Ráfagas. El actuador no emite una entrada. Emite una ráfaga: un programa temporizado de entradas ejecutado por un ejecutor dedicado sin modelo en el bucle.
g:0;c:l;w:150;t:"README.md";k:enter;w:80;k:ctrl+sEso es una decisión y siete entradas que abarcan ~400 ms, programadas al milisegundo. Una ráfaga de 40 acciones sigue costando una decisión. La tasa de entrada la fija la ráfaga, no el modelo.
Reflejos. Reglas que se disparan con sondas de pantalla baratas — un píxel, un promedio de región — en microsegundos, entre decisiones, sin ningún modelo.
{"id": "heal", "when": "probe('health') < 0.25", "do": "k:q;w:60", "cooldown_ms": 800}Omitir la percepción. La mayoría de los ciclos miran una pantalla que no ha cambiado. Una diferencia de fotograma de 40 µs decide si gastar 300 ms en el modelo de visión o reutilizar la última observación. En trabajo de escritorio ordinario esto omite el VLM en la mayoría de los ciclos.
Localidad de caché de prefijo. Los prompts se ordenan primero-estático para que llama.cpp reutilice la caché KV y solo re-procese la cola cambiada.
Por qué los modelos pequeños son fiables a pesar de ser pequeños
Porque no se les pide que sean fiables — están restringidos.
Bajo llama.cpp, ambos modelos generan contra una gramática GBNF que se regenera cada ciclo a partir del estado actual. La gramática no es un consejo. Enmascara los logits para que solo los tokens que continúan un análisis válido sean alcanzables. Concretamente, el actuador no puede:
emitir una ráfaga malformada
nombrar una tecla que la política deniegue — la tecla no está en la gramática
referenciar un elemento que no fue observado — el rango de índices se construye a partir del recuento de elementos de este ciclo
proponer una transición de estado que el Playbook no haya declarado
Y el modelo de visión no puede inventar un nombre de elemento de interfaz: su vocabulario de etiquetas es la lista watch que escribiste, más un pequeño conjunto genérico. Así que una guarda sees("address bar") compara contra un vocabulario cerrado en lugar de contra cualquier sustantivo que un modelo de 3B haya decidido producir.
No hay bucle de reintento ni análisis JSON defensivo, porque la salida malformada no es improbable — es irrepresentable.
El Playbook
No le das a los modelos pequeños un objetivo. Les das una máquina de estados. Las transiciones son expresiones de guarda evaluadas por el runtime, no por un modelo.
{
"name": "open_downloads",
"goal": "Open the file manager at ~/Downloads. Delete nothing, confirm nothing.",
"initial": "launch",
"policy": {
"dry_run": true,
"allow_verbs": ["g", "c", "k", "t", "w"],
"deny_labels": ["delete", "trash", "confirm", "empty trash"]
},
"budget": { "max_cycles": 60, "max_seconds": 90 },
"states": {
"launch": {
"brief": "Open the application launcher and start the file manager.",
"watch": ["application launcher", "search field", "file manager icon"],
"on_enter": "k:meta;w:400",
"transitions": [
{ "when": "sees('search field')", "to": "type_name" },
{ "when": "cycles() > 6", "to": "@failure", "note": "launcher never opened" }
]
},
"navigate": {
"brief": "Focus the location bar with ctrl+l, type the path, press Enter.",
"watch": ["location bar", "file list", "error message"],
"on_enter": "k:ctrl+l;w:200",
"transitions": [
{ "when": "text('Downloads')", "to": "@success" },
{ "when": "sees('error message')", "to": "@failure" }
]
}
},
"success_when": "text('Downloads') and not flag('loading')"
}voltage_reference devuelve el DSL completo, el esquema JSON y la tabla de funciones de guarda, para que un orquestador pueda crear uno sin leer este repositorio.
Ajuste de rendimiento
Todos los números siguientes están medidos en la máquina de referencia (portátil RTX 3050 6 GB, Qwen2.5-VL-3B + Qwen3-1.7B bajo llama.cpp), no derivados.
Ambos modelos están limitados por decodificación. Los tokens de salida son la única palanca que importa.
Eso fue una sorpresa — el diseño originalmente asumía que la visión estaba limitada por prefill, y no lo está. El prefill midió ~28 ms y plano de 448×252 a 896×504. La decodificación corre a ~22 ms/token. Así que:
qué | coste |
un token de salida | ~22 ms |
un elemento informado | ~21 tokens ≈ 500 ms |
visión, 2 elementos | ~1.0 s |
visión, 4 elementos | ~2.2 s |
actuador, prefijo en caché | 140–400 ms según la longitud de la nota |
Tres consecuencias, cada una de las cuales cambió un valor por defecto:
max_elementses el coste dominante de la visión. El valor por defecto es 3. Subirlo a 6 añade ~1.5 s por ciclo percibido. Ponlo al número que tus guardas realmente comprueban.Reducir
downscale_tono ayuda y normalmente perjudica. 448×252 midió 2.5× más lento que 896×504 — una imagen más borrosa hace que el modelo esté menos seguro, así que emite más tokens. Usa el tamaño más grande que quepa.El campo
notedel actuador costaba el 55% de su latencia. Es puramente diagnóstico, y a 48 caracteres midió 412 ms/ciclo frente a 184 ms a 12 caracteres y 140 ms a 0. El valor por defecto ahora es 12.
Los elementos se codifican como [label_index, x1, y1, x2, y2] en lugar de {"l":"address bar","b":[...],"c":0.9} por la misma razón — medido 27–29% menos tokens y 32–41% menos latencia. Indexar en el vocabulario cerrado watch también es más seguro: el modelo no puede deletrear una etiqueta, y mucho menos escribirla mal.
La evaluación GBNF se ejecuta en la CPU una vez por token muestreado, así que el actuador recibe más hilos de CPU que el modelo de visión a pesar de estar completamente descargado a GPU — y restringir allow_keys es una optimización de latencia, no solo de seguridad.
Dos ajustes que fallan silenciosamente si están mal:
GGML_CUDA_FA_ALL_QUANTS=ONen tiempo de compilación. Servimos con caché KVq8_0y atención flash. Sin esta bandera llama.cpp no compila kernels de FA para esa combinación de KV y cae a una ruta lenta — sin error, solo números misteriosamente malos.scripts/build-llama.shla establece.GGML_CUDA_ENABLE_UNIFIED_MEMORY=0en tiempo de ejecución. Si es1, el desbordamiento de VRAM se derrama silenciosamente por PCIe en lugar de fallar. Todo funciona y es ~10× más lento.serve.shlo fija a off.
Mide en lugar de adivinar:
.venv/bin/voltage benchManeja ambos backends con las formas exactas de prompt que usa el bucle e informa de la latencia en frío vs. con prompt en caché, ms-por-token-visual en tres tamaños de entrada, y el tiempo de ciclo que implican. Una aceleración de caché de prompt por debajo de ~1.5× significa que algo dinámico se filtró al prefijo del prompt.
Comparando modelos
El experimento obvio — "qué modelo escribe mejores ráfagas" — mide lo incorrecto. La gramática ya garantiza que cada ráfaga es válida, así que un modelo más grande no puede ganar en sintaxis. Lo que realmente decide si una configuración es utilizable:
Precisión de anclaje. Un modelo que es 200 ms más rápido y 40 px desviado es inútil — el clic falla. Medido como distancia del centro en píxeles de pantalla, no IoU, porque un clic aterriza en el centro.
Calidad de decisión bajo restricción. Dada la misma observación, ¿elige la acción legal correcta, y encadena una secuencia completa en una ráfaga en lugar de emitir una acción tímida por ciclo?
Latencia, que solo importa una vez que 1 y 2 son aceptables.
.venv/bin/voltage fixture desktop # capture a real screen
.venv/bin/voltage compare # score whatever is running nowLa verdad de referencia proviene de capturas de pantalla reales etiquetadas por el modelo orquestador — que es la misma referencia que este sistema usa en tiempo de ejecución. La interfaz sintética es una trampa: un rectángulo dibujado no se lee como un botón a un modelo entrenado con interfaces reales, así que puntuar contra ella mide la habilidad equivocada.
Los resultados se acumulan entre ejecuciones, así que el flujo de trabajo es: servir perfil A → compare → servir perfil B → compare → leer la tabla. voltage compare --list la imprime sin volver a ejecutar.
Los fixtures son tuyos y no se commitean. Añade fixtures/ a .gitignore si tus capturas de pantalla contienen algo privado.
El bucle de aprendizaje
El primer playbook para un objetivo desconocido casi nunca es correcto. Lo que importa es que los fallos sean específicos, y que el siguiente intento comience desde lo que el último aprendió.
voltage_reference(section="loop") the loop itself, and what each failure means
voltage_reference(section="bursts") the burst cookbook: chaining, timing, game patterns
voltage_capture / voltage_observe look before writing — check your labels exist
voltage_validate_playbook dead guards, unreachable states, caught statically
voltage_run(dry_run=true) real models, real screen, nothing injected
voltage_diagnose(run_id) ← what to change, not raw data
voltage_learn(target=..., note=...) record it; persists across sessions
voltage_lessons(target=...) recall it before the next playbookvoltage_diagnose es la pieza que convierte esto en un bucle. Calcula lo que el diario implica pero no declara, y nombra la edición para cada cosa. En una ejecución atascada de Minecraft:
[BLOCKER] label_never_seen never reported: ['crosshair', 'health bar']
[BLOCKER] input_not_landing 14 bursts executed, but the screen never changed
[BLOCKER] state_never_left 'mine' ran 14 cycles and never transitioned
[PROBLEM] timid_bursts bursts averaged 1.0 actions
[HINT] vision_every_cycle vision ran on 100% of cyclesLa distinción para la que existe: una ráfaga que nunca se ejecutó y una ráfaga que se ejecutó y no hizo nada se ven idénticas en un resumen y tienen causas no relacionadas. La primera es política o gramática. La segunda es foco de ventana, modo de puntero, o una aplicación que ignora la entrada sintética. Diagnose las separa comprobando si el fotograma realmente cambió después de la ejecución.
Aplica el hallazgo de mayor severidad, vuelve a ejecutar, diagnostica de nuevo. Un cambio a la vez — varios a la vez hacen que el siguiente diagnóstico sea ininterpretable.
Las lecciones persisten entre sesiones, con clave por objetivo, así que el segundo playbook para un juego comienza desde las coordenadas de sonda y los nombres de etiqueta funcionales que el primero descubrió:
voltage_learn(target="minecraft", kind="label",
note="vision reports 'hotbar' reliably but never 'crosshair'")
voltage_learn(target="minecraft", kind="timing",
note="block placement needs w:100 after right click or it does not register")Seguridad
Lo que genera entradas es un modelo de 1.7B. El gobernador es la capa que no es consultiva: cada ráfaga pasa a través de él, incluidas las ráfagas de reflejo y las que escribiste tú mismo.
dry_runes el valor por defecto. Un Playbook nuevo analiza, comprueba y registra cada ráfaga sin tocar nada.Rechazo de ráfaga completa. Ejecutar a medias una secuencia prevista es peor que no ejecutarla.
deny_labelsrechaza un clic en cualquier cosa llamada Delete / Confirm / Purchase / Allow, dondequiera que aparezca — esto es lo que atrapa el diálogo que aparece en algún lugar inesperado.Cercado de regiones, listas blancas de teclas, acordes denegados (
ctrl+alt+delete,alt+f4), patrones de texto denegados (rm -rf,sudo), límites de tamaño de ráfaga y de entradas por segundo.Cuatro paradas independientes:
voltage stop(escribe un archivo — funciona por SSH), un temporizador de hombre muerto que se dispara en su propio hilo si el bucle se atasca, contención de entrada física (toca el ratón real y se detiene), y presupuestos del Playbook.Las teclas mantenidas siempre se liberan — al abortar, al fallar, al expirar. Una ejecución interrumpida entre
d:shiftyu:shiftno debe dejar Shift pulsado.
Instalación
De nada a funcionando, dos comandos.
Linux / macOS
git clone https://github.com/casualkre/voltage-input-mcp && cd voltage-input-mcp && ./install.shWindows (PowerShell)
git clone https://github.com/casualkre/voltage-input-mcp; cd voltage-input-mcp; powershell -ExecutionPolicy Bypass -File .\install.ps1Después, en cualquiera de los dos:
voltage setupinstall.sh se encarga de Python, los paquetes del sistema, el venv y tu PATH, e imprime las líneas sudo exactas para cualquier cosa que necesite root en lugar de pedirlo. voltage setup entonces detecta lo que ya tienes, descarga solo lo que falta, inicia los servidores de modelos, y se registra con tu cliente de IA — ejecutando cada paso, no describiéndolo. De diez a veinticinco minutos, casi todo tiempo de descarga. Seguro de re-ejecutar; retoma donde lo dejó.
Entonces solo ejecuta:
voltageSetup detecta lo que ya tienes y continúa desde ahí. No asume un punto de partida: sondea tu SO, GPU, si llama.cpp u Ollama está instalado, qué modelos ya están descargados, si la entrada y la captura funcionan, y si el servidor MCP está registrado — entonces planifica solo los pasos que realmente quedan, y dice cuáles necesitan una decisión tuya y cuáles puede simplemente hacer. Si ya tienes Ollama, lo usa. Si no tienes ningún backend, explica el trade-off en dos líneas y te deja elegir.
Sin argumentos abre una consola interactiva: estado en vivo, setup guiado que arregla lo que no esté listo en orden de dependencias, un selector de modelos, un editor de configuración, registro con una tecla en Claude Code, y diagnósticos. Cada subcomando siguiente sigue funcionando de forma no interactiva, así que los scripts y CI no se ven afectados.
██╗ ██╗ ██████╗ ██╗ ████████╗ █████╗ ██████╗ ███████╗
██║ ██║██╔═══██╗██║ ╚══██╔══╝██╔══██╗██╔════╝ ██╔════╝
██║ ██║██║ ██║██║ ██║ ███████║██║ ███╗█████╗
╚██╗ ██╔╝██║ ██║██║ ██║ ██╔══██║██║ ██║██╔══╝
╚████╔╝ ╚██████╔╝███████╗██║ ██║ ██║╚██████╔╝███████╗
╚═══╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝
── status ──────────────────────────────────────────────
ok input device /dev/uinput
ok vision model http://127.0.0.1:8080
ok actuator model http://127.0.0.1:8081
ok mcp registered claude mcp list
ok voltage on PATH ~/.local/bin/voltagePerfiles experimentales
Listados por separado en voltage → models, cada uno detrás de una advertencia que debes aceptar. Existen porque las mediciones hacen que los trade-offs sean predecibles: la decodificación domina a ~22 ms/token y escala con los parámetros activos, así que reducir los modelos realmente aumenta la tasa del bucle. Lo que cuesta es el anclaje.
perfil | modelos | VRAM | intercambio |
| SmolVLM-500M + Qwen3-0.6B | ~2.2 GB | 3–4× la tasa de bucle, el grounding apenas funciona |
| Qwen2.5-VL-3B + Qwen3-0.6B | ~3.8 GB | decisiones más rápidas, grounding sin cambios |
| Qwen2.5-VL-32B + Qwen3-14B | ~34 GB | mejor grounding, 1–2.5 s/ciclo |
| Qwen2.5-VL-32B + Qwen3-30B-A3B | ~43 GB | capacidad de 30B a velocidad de decodificación de ~3B |
| 3B + 0.6B en CPU | ninguno | funciona sin GPU, segundos por ciclo |
Dos merecen mención especial:
hyper es el peligroso. SmolVLM-500M no es un modelo de grounding. Devolverá
cajas y a menudo serán incorrectas — y una caja incorrecta es un clic en el lugar equivocado, no
una degradación elegante. Úsalo solo donde watch esté vacío (las sondas y reflejos hacen el
trabajo real) o donde cada clic esté delimitado por click_allow_regions y
require_target_element.
beefy_moe es el interesante. Qwen3-30B-A3B es una mezcla de expertos con ~3B
activos de parámetros, por lo que decodifica aproximadamente a velocidad de 3B mientras razona con capacidad de 30B —
y la decodificación es precisamente lo que limita este bucle. Un actuador mucho mejor que un denso
14B con latencia similar. El inconveniente es la memoria: solo los expertos activos son rápidos, no
los pesos, por lo que los 30B completos deben residir en memoria.
recommend() nunca devuelve un perfil experimental, y una prueba lo verifica.
Perfiles de modelo personalizados
Los perfiles integrados cubren las máquinas contra las que se desarrolló esto, no las tuyas. Añade
los tuyos desde voltage → perfiles, o editando profiles.toml junto a tu configuración:
[my_rig]
description = "RTX 4090"
[my_rig.vision]
hf_repo = "ggml-org/Qwen2.5-VL-7B-Instruct-GGUF"
hf_file = "Qwen2.5-VL-7B-Instruct-Q4_K_M.gguf"
mmproj_file = "mmproj-Qwen2.5-VL-7B-Instruct-Q8_0.gguf"
params_b = 7.0
weights_mb = 4700
n_ctx = 4096
port = 8080
[my_rig.actuator]
hf_repo = "unsloth/Qwen3-4B-Instruct-2507-GGUF"
hf_file = "Qwen3-4B-Instruct-2507-Q4_K_M.gguf"
params_b = 4.0
weights_mb = 2500
port = 8081Los perfiles personalizados se fusionan sobre los integrados por nombre, por lo que nombrar uno lean reajusta el
integrado sin bifurcar el paquete. Usa ollama_tag en lugar de hf_repo/hf_file para
el backend de Ollama.
Una ranura es exigente y la otra no. La visión debe poder emitir cajas delimitadas (grounded bounding boxes) cuando se le pida — Qwen2.5-VL, Qwen3-VL, InternVL, MiniCPM-V y UI-TARS pueden; un captioner general describirá tu pantalla maravillosamente y pondrá las cajas en el lugar equivocado. El actuador es indulgente: bajo una gramática GBNF, elige entre un puñado de continuaciones legales, por lo que casi cualquier modelo instruct competente de 1B+ funciona.
Comandos de shell vs herramientas MCP
Dos superficies diferentes, y mezclarlas es el primer tropiezo habitual:
invocado | aspecto | |
comando de shell | escrito en una terminal, con un espacio |
|
herramienta MCP | pedido a Claude, con un guion bajo |
|
voltage_doctor es un nombre de herramienta en el espacio de nombres de Claude, no un programa en disco. Escribirlo en
una terminal siempre dirá "comando desconocido". Pide a Claude que lo ejecute en su lugar.
Eso comprueba el acceso a /dev/uinput, instala dependencias del sistema, crea el venv y
imprime lo que falta. Luego:
./scripts/fetch-models.sh lean && ./scripts/serve.sh lean.venv/bin/voltage doctorConectándolo a un cliente
voltage connectMuestra lo que está configurado, las URLs en vivo, si los modelos están activos y si el servidor está registrado — luego da pasos de copiar y pegar por cliente con tus rutas reales y el entorno ya completados:
voltage connect --client claude-desktop
voltage connect --client cursor
voltage connect --json # just the mcpServers entryCubiertos: Claude Code, Claude Desktop, conector personalizado de claude.ai, Cursor, Windsurf, Zed
y un bloque mcpServers genérico para cualquier otra cosa. Lo mismo es la pantalla 4 en la
consola de voltage, que también puede escribir la configuración de Claude Desktop por ti (haciendo una copia de seguridad del
archivo existente primero, y negándose a tocarlo si no es JSON válido).
Cada configuración generada lleva el entorno de sesión explícitamente, porque eso es lo que
sale mal: un servidor registrado desde un shell sin
DBUS_SESSION_BUS_ADDRESS se conecta correctamente y está silenciosamente ciego — la entrada funciona,
la captura de pantalla no. voltage connect detecta ese caso y lo dice.
Añadiéndolo como conector personalizado
Los clientes que añaden servidores MCP por URL necesitan HTTP en lugar de stdio:
voltage serve --httpLuego añade http://127.0.0.1:8765/mcp como conector personalizado.
El enlace está restringido a loopback, y se requiere --allow-remote para cambiarlo.
Eso no es un relleno: este servidor existe para mover el ratón, pulsar teclas y leer la
pantalla, y MCP no tiene autenticación propia. Un enlace no-loopback publica
control remoto no autenticado de tu escritorio. Si realmente lo necesitas, pon un
proxy inverso autenticado delante y entiende que quien alcance el puerto posee la
máquina.
Lanzamiento desde un cliente MCP
Los clientes MCP inician servidores con un entorno saneado — PATH, HOME y poco
más. Ese es un valor predeterminado sensato y rompe la captura de pantalla, porque llegar al
compositor necesita DBUS_SESSION_BUS_ADDRESS y WAYLAND_DISPLAY. La inyección de entrada aún
funciona sin ellos (uinput es un archivo de dispositivo, no un servicio de sesión), por lo que el fallo parece
confusamente parcial: las ráfagas se ejecutan, las capturas de pantalla no.
Pásalos explícitamente:
claude mcp add voltage-input \
-e WAYLAND_DISPLAY="$WAYLAND_DISPLAY" \
-e DISPLAY="$DISPLAY" \
-e DBUS_SESSION_BUS_ADDRESS="$DBUS_SESSION_BUS_ADDRESS" \
-e XDG_RUNTIME_DIR="$XDG_RUNTIME_DIR" \
-- /absolute/path/to/voltage-input-mcp/.venv/bin/voltage-input-mcpvoltage_doctor informa exactamente cuáles de estos faltan, así que si la captura está fallando, ese es
el primer lugar donde mirar.
Plataformas
entrada | captura | texto | |
Linux |
| portal→PipeWire, KWin DBus, grim, X11 | scancodes, respaldo de portapapeles para no-ASCII |
Windows |
| GDI |
|
Todo lo que está por encima del sumidero de entrada — programación de ráfagas, temporización, seguimiento de teclas mantenidas, el
gobernador de seguridad, todo el runtime — es compartido. Cada plataforma implementa cinco métodos
(key, button, move_abs, move_rel, scroll); ver inputs/sink.py.
Dos asimetrías que vale la pena conocer:
Escribir es más correcto en Windows.
KEYEVENTF_UNICODEentrega una unidad de código UTF-16 sin involucrar la distribución del teclado. El uinput de Linux envía scancodes, por lo que la puntuación en una distribución no estadounidense sale mal — silenciosamente — por eso existe el respaldo de portapapeles allí y no se necesita en Windows.La captura es más capaz en Linux. GDI
BitBltno puede ver algunos videos de superposición de hardware y juegos exclusivos en pantalla completa; esos se capturan en negro. Ejecuta tales juegos en modo ventana sin bordes.
En Windows, SendInput no puede controlar ventanas propiedad de un proceso elevado (UIPI) — esto
falla silenciosamente, por lo que voltage doctor informa tu estado de elevación. La conciencia de DPI se
declara en la importación; sin ella, cada coordenada es incorrecta en una pantalla escalada.
Requisitos
Linux (cualquier servidor de visualización) o Windows 10/11
Python 3.11+
Una GPU con ~5 GB libres para el perfil
lean;voltage profilesmuestra lo que cabe en la tuyallama.cpp para la ruta rápida, o Ollama para una ruta más lenta sin compilación
Verificado de extremo a extremo en KDE Plasma 6 / Wayland / CUDA / Python 3.14. Las rutas de Windows están implementadas y verificadas por tipos, pero no se han ejecutado en una máquina Windows — trátalas como no probadas e informa lo que se rompa.
Al orquestador se le dice qué compilación está manejando
El mismo Playbook es sólido en una configuración y incorrecto en otra, y un modelo remoto no puede ver cuál. Por lo tanto, las instrucciones MCP del servidor se construyen al inicio a partir de la configuración en vivo, y llevan solo las líneas que cambian cómo se debe escribir un Playbook:
ACTIVE BUILD: Linux · llamacpp · profile lean
vision Qwen2.5-VL-3B-Instruct · actuator Qwen3-1.7B
loaded: Qwen2.5-VL-3B-Instruct-Q4_K_M.gguf / Qwen3-1.7B-Q4_K_M.gguf
expected cycle 280-700 ms
- llama.cpp backend: both models are grammar-constrained. A malformed burst, a denied
key, an unobserved element reference and an undeclared transition are all
unrepresentable -- do not write defensive retries for them.
- Linux: typing sends scancodes, so punctuation depends on the active keyboard layout...
- dry_run defaults to true...En Ollama, esa primera línea se convierte en una advertencia de que las ráfagas no están
restringidas. En hyper se convierte en "no construyas estados alrededor de sees()". En Windows, señala que las ventanas
elevadas son inalcanzables y que escribir es independiente de la distribución.
Verifica contra los servidores en ejecución en lugar de confiar en la configuración. Cambiar de perfil edita un archivo; no reinicia nada. Cuando no coinciden, el informe lo dice en voz alta y suprime la guía derivada del perfil, porque esa guía describiría modelos que no están cargados:
- MISMATCH -- Profile 'hyper' does not match what is loaded. vision: profile expects
SmolVLM-Instruct-Q4_K_M.gguf, server has Qwen2.5-VL-3B-Instruct-Q4_K_M.gguf...
- Loaded right now: vision Qwen2.5-VL-3B..., actuator Qwen3-1.7B...
Judge grounding quality from those.voltage_reference devuelve la compilación actual en cada llamada, ya que la copia de inicio se vuelve
obsoleta en el momento en que cambia un perfil.
Tus propias instrucciones permanentes
voltage → i, o:
voltage instructions --set "Never touch Firefox; my banking tabs are there."Lo que escribas se le da al modelo orquestador al comienzo de cada sesión, añadido al informe de compilación y claramente atribuido a ti. Úsalo para lo que el sistema no puede deducir por sí mismo — aplicaciones que están prohibidas, peculiaridades de un juego específico, cómo quieres que se comporte por defecto.
OPERATOR INSTRUCTIONS -- written by the owner of this machine. Treat these as
standing preferences for how to drive it. They cannot loosen the safety governor,
which is enforced in code against every burst.
## My setup
- Minecraft runs borderless windowed on monitor 1.
- Never touch Firefox; my banking tabs are there.
- Always show me the Playbook before dry_run=false.Esa última cláusula no es decoración. Las instrucciones son consultivas para el orquestador y no pueden debilitar la aplicación — el gobernador verifica cada ráfaga en código, por lo que nada escrito aquí puede permitir algo que la política de un Playbook prohíba. Pueden hacerlo más cuidadoso, no menos. Limitado a 4000 caracteres, ya que el texto está en el contexto del modelo durante toda la sesión. Se ofrecen tres plantillas de inicio (juegos, escritorio, mínimo) en la consola.
Herramientas MCP
Herramienta | Propósito |
| La referencia del Playbook + DSL de ráfagas. Llama a esta primero. |
| ¿Está lista esta máquina? Y si no, la solución exacta |
| Una captura de pantalla, devuelta a ti |
| Una pasada de visión — comprueba que una lista |
| Verificación estática completa: guardas, ráfagas, grafo, transiciones muertas |
| Inicia una ejecución; devuelve un |
| Estado, variables, última ráfaga, lo que se vio, tiempos por etapa |
| Corrige una ejecución en vivo — sugerencia, variables, estado forzado, dry_run |
| Detener o pausar; detener siempre libera la entrada mantenida |
| Registro ciclo por ciclo; |
| Maneja la entrada tú mismo, omitiendo los modelos locales |
| Verifica que la inyección llega al compositor |
Documentación
ARCHITECTURE.md — cómo funciona el bucle, por qué se tomó cada decisión, dónde se va el tiempo
PLAYBOOK.md — la guía de autoría
Estado
Construido y verificado hasta donde se puede sin pesos en disco. 149 pruebas cubren el DSL de
ráfagas, el sandbox de guardas, el gobernador de seguridad, la compilación de playbooks, la generación de GBNF, la
codificación de cable de uinput y el propio bucle de ejecución (manejado con modelos simulados — incluyendo una verificación
de que la percepción on_change realmente omite el modelo de visión en una pantalla estática).
El servidor MCP se manejó de extremo a extremo sobre stdio por un cliente real: 13 herramientas, esquemas
correctos, execute_burst aceptó una ráfaga válida y rechazó sudo rm -rf / con ambas
reglas coincidentes.
Lo que no se ha ejecutado es un modelo en vivo: eso necesita llama.cpp compilado y pesos descargados,
lo cual scripts/ configura. Dos cosas tampoco se activaron deliberadamente durante la
compilación — el diálogo de permiso del portal y cualquier inyección de entrada real — ya que ambas actúan en
tu escritorio.
Orden de operaciones desde aquí:
./scripts/setup.sh # reports what needs sudo, doesn't run it
./scripts/build-llama.sh # ~15 min with CUDA
./scripts/fetch-models.sh lean
./scripts/serve.sh lean
.venv/bin/voltage doctor # should now say READYLuego, en un cliente MCP: voltage_calibrate (observa cómo se mueve el cursor),
voltage_observe (comprueba que el modelo de visión encuentra tus etiquetas), luego un Playbook
de dry_run y lee voltage_journal antes de establecer dry_run=false.
Autoría
Escrito de principio a fin por Claude Opus 5 (Anthropic) en una sola sesión: arquitectura, implementación, pruebas y documentación. Un humano especificó la idea, estableció las restricciones (KDE Wayland, 6 GB de VRAM, "más rápido que computer-use") y revisó el resultado, pero no escribió el código.
Los hallazgos sobre la plataforma integrados en este repositorio provienen de sondear la máquina
durante la compilación, no de suposiciones: que KWin rechaza ScreenShot2 para ejecutables no
incluidos en la lista de permitidos, que grim no funciona bajo KWin, que los clientes MCP
eliminan el bus de sesión. Cada uno está documentado en el punto del código donde obligó a tomar
una decisión.
LICENSE no nombra a ningún individuo como titular de los derechos de autor, y el razonamiento
está escrito allí.
Licencia
MIT. Consulta LICENSE.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
Let ChatGPT, Claude & Cursor use your Mac: email, calendar, iMessage, Teams, files. Local, free.
Adaptive plan/build/review cycles for AI coding assistants, persisted across sessions.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/casualkre/voltage-input-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server