@grip-labs/wadington
v0.3.3
Published
WAD Agent y WAD Harness: el agente de manejo de dinero. Politica antes de cada pago, libro de todo intento, y un piso de capacidades que el agente no puede levantar.
Downloads
646
Readme
Wadington · WAD Agent · WAD Harness
Instalar
curl -fsSL https://harness.wad.cash/install | sh
wadLa primera vez que escribís wad, Wadington nace: se presenta, te pregunta
con qué modelo pensar (DeepSeek, Claude, ChatGPT u OpenRouter), prueba tu key
de verdad y la guarda en el Llavero de tu Mac. No hay archivos que editar. De
ahí en más, wad lo despierta y se acuerda de lo que hablaron.
wad # hablar con Wadington
wad web # la misma conversación, en el navegador
wad "¿cuánto tengo?" # una pregunta suelta
wad modelo # cambiar el modelo con el que piensaTodo lo suyo vive en ~/.wad. El instalador (instalar.sh) usa tu Node si es
22.19 o más nuevo; si no, baja el oficial y verifica su checksum. No pide
sudo.
Dale plata a tu agente. No le des el control.
Un agente que maneja dinero, con una correa que él no puede aflojar. Se usa de dos maneras, según si ya tenés agente o no.
Si ya tenés uno, WAD Agent se instala como servidor MCP y entra en cualquier runtime que hable MCP: Claude Code, Cursor, Open WebUI, LibreChat, el DeepSeek Harness. Una integración, todos los destinos.
WAD_TOKEN=tu_token npx -p @grip-labs/wadington wad-agentSi no tenés, está WAD Harness: el agente entero, con su propio harness, armado desde cero para que no pueda hacer nada que no sea manejar plata. Más abajo.
Las dos superficies leen el mismo catálogo y aplican la misma política. No pueden divergir: hay un test que lo verifica.
Por qué existe
WAD ya resuelve la mitad difícil: custodia, liquidación on-chain, política del lado del servidor. Pero el agente corre en la máquina del cliente, y entre el agente y WAD no hay nada.
WAD Agent es ese "nada". Tres cosas que solo se pueden hacer del lado del cliente:
La política vive en tu disco. Se lee entera antes de cada pago y no existe ninguna herramienta que la escriba. Un prompt malicioso puede convencer al modelo de cualquier cosa; se choca contra el archivo igual.
Un pago fuera de límite no llega al proveedor. La decisión se toma antes de la red. No reserva fondos, no deja registro ajeno, y no depende de que nadie esté de acuerdo.
Queda rastro de lo que NO se hizo. El historial de un proveedor lista lo que aceptó. El libro guarda también lo que se frenó y por qué. Eso es lo que contesta "por qué el agente no pagó" sin adivinar.
Lo que ve el agente
| Herramienta | Qué hace |
|---|---|
| wad_saldo | Disponible, reservado, lo que está entrando on-chain y cuánto queda de presupuesto |
| wad_pagar | Paga, aplicando política antes de mover un peso |
| wad_politica | Los límites vigentes y cuánto queda. Solo lectura |
| wad_libro | Los movimientos, incluidos los frenados |
| wad_estado_pago | Estado de un pago, con comprobante on-chain |
WAD Harness
Hay cientos de harness para agentes. Ninguno es de manejo de dinero.
Y no alcanza con agarrar uno y colgarle una herramienta de pagos, porque están construidos para lo contrario de lo que necesita la plata. Un harness de código maximiza lo que el agente alcanza — y está bien, porque ahí el peor caso es un archivo mal escrito. Con dinero el peor caso es que la plata se vaya, y eso no se revierte.
Por eso WAD Harness no se define por lo que agrega sino por lo que saca.
El perfil base típico monta shell, filesystem con escritura, web_fetch,
subagentes, un loop autónomo de 64 rondas y telemetría a un tercero. Si a eso le
colgás un pagar, no construiste un agente con dos herramientas: construiste
uno al que alcanza con engañarlo una sola vez.
Lo que este agente NO puede hacer
| Apagado | Por qué |
|---|---|
| bash, pwsh | Con shell, cualquier límite se esquiva por abajo: el agente escribe su propio cliente y paga sin pasar por la política |
| read, write, grep, glob | La política es un archivo. Si puede escribir, afloja su propia correa, y el libro deja de ser append-only |
| web_fetch, web_search | El destino de un pago nunca puede salir de algo que el agente leyó por ahí. Esa es la forma exacta de la inyección de prompt que acá cuesta la plata |
| subagent, fork, workflow | Un hijo heredaría la billetera sin heredar el contexto, y el tope por sesión es ficción cuando hay N sesiones |
| ralph | 64 rondas autónomas con una billetera colgada es un loop que gasta 64 veces sin que nadie mire |
| exit_plan_mode | Es para que un agente de código presente un plan antes de tocar archivos. Acá no hay archivos, y una herramienta visible que siempre se niega solo invita a intentarla |
| skill | Instrucciones de terceros que el agente carga y obedece: una puerta de entrada, no una funcionalidad |
| telemetría | Un agente que maneja plata ajena no le cuenta a un tercero lo que hace |
Además clava dos cosas que en el base salen de variables de entorno: hoy
DSH_PERMISSION_MODE=danger-full-access apaga el pedido de aprobación
humana. Acá el sandbox es read-only y la aprobación es ask, y no se
configuran desde afuera del archivo de política.
Por qué no se puede deshacer
Apagar filas en el perfil es composición, y un patch posterior las puede volver
a prender. Por eso hay una segunda capa que no depende de eso: una lista
blanca aplicada con ctx.tools.guard(), el guard monotónico del harness.
La garantía está en el tipo, no en la documentación:
type ToolGuard = (execution) => string | undefinedNo existe ningún valor de retorno que signifique permitir. Un guard solo puede negar (devolviendo el motivo) o no opinar. Por eso ningún plugin que cargue después, en ningún orden, puede convertir una negación en permiso: la operación no existe. Y como la lista es blanca, una herramienta que alguien agregue el mes que viene ya está negada sin que nadie toque el archivo.
Verificalo vos
Dos comandos. El primero prueba el piso sin levantar nada; el segundo le pide al harness que componga el perfil y verifica el resultado contra lo que este README promete, fila por fila.
npm test # 60 pruebas; 7 del piso
node harness/verificar-perfil.mjs /ruta/al/deepseek-harness
node harness/verificar-perfil.mjs /ruta/al/deepseek-harness wad # un perfil ya instaladoOK tool-bash apagada
OK tool-fs apagada
OK tool-web apagada
...
OK sandbox-policy.config.mode = read-only
OK approval.config.policy = ask
OK presets = read-only
OK ninguna herramienta del harness quedo viva
El perfil cumple: 89 filas compuestas, 19 capacidades apagadas.Esa última línea es la que importa a futuro: si una versión nueva del harness agrega una herramienta, el verificador falla en vez de dejarla aparecer sola en un agente que maneja plata. Alguien tiene que decidir a mano si entra. Encontró dos el primer día que corrió.
Usarlo
node harness/instalar.mjs /ruta/al/deepseek-harness # perfiles + comando wad-harness
echo "<token>" > ~/.wad-token && chmod 600 ~/.wad-token
wad-harness # la conversacion en la terminal
wad-harness web # la misma, en el navegador
wad-harness tarea "..." # una tarea y salewad es una conversación en la terminal que se retoma: el id queda en
~/.wad/conversacion y la próxima vez sigue desde ahí. /nueva empieza de
cero, /razonamiento muestra lo que piensa el modelo, Ctrl-C corta un turno.
Un pago arriba del umbral blando pregunta [s/N] en la terminal. Lo que
tipeaste mientras el agente trabajaba queda en cola como próximo mensaje, pero
nunca contesta una aprobación: la pregunta descarta la cola y espera una
línea escrita después de verla. Algo pegado de antemano no puede aprobar un
pago.
wad-tarea corre una sola tarea y sale, para scripts y crons. No tiene a quién
preguntarle, así que un pago que pide aprobación no sale.
wad-web es la misma conversación en el navegador: la terminal y la web
retoman la misma, y si una ya la tiene abierta la otra no arranca (en vez de
empezar otra y pisar la guardada).
wad-harness web
# Abrí: http://127.0.0.1:4747/?t=... (WAD_WEB_PUERTO cambia el puerto)No usa la interfaz web del harness: esa es un IDE de código y con el perfil de dinero se cuelga. Es un servidor chico con una sola página, que cuida lo que importa cuando del otro lado hay una billetera:
- escucha solo en
127.0.0.1y rechaza cualquier otroHost(DNS rebinding); - se entra con el link que imprime la terminal; el token se cambia por una
cookie
HttpOnly; SameSite=Strict, y toda la API la exige; - los POST exigen JSON y una cabecera propia, que un formulario ajeno no manda;
- CSP
default-src 'self', sin nada inline, y el texto del modelo se arma con nodos del DOM: una respuesta con HTML se ve como texto; - un pago arriba del umbral aparece como tarjeta con Aprobar / Rechazar, y solo se puede contestar con el id que se generó al mostrarla. No existe forma de aprobarlo por adelantado.
Configuración
WAD_TOKEN=... # obligatorio: pareá un agente en la consola de WAD
WAD_POLITICA=~/.wad/politica.yaml
WAD_LIBRO=~/.wad/libro.jsonl
WAD_DEPOSIT_ADDRESS=0x... # opcional, habilita ver los depósitos entrandoCopiá politica.ejemplo.yaml a ~/.wad/politica.yaml. Sin archivo, los
límites por defecto son deliberadamente bajos: es preferible que el primer
pago se frene a que se escape.
Los cuatro límites, y por qué no se comportan igual
| Límite | Al pasarse | ¿Una persona puede aprobarlo igual? |
|---|---|---|
| porPago | rechaza | no |
| porDia | rechaza | no |
| total | rechaza | no |
| aprobacion.arribaDe | escala a una persona | sí |
Los tres primeros son duros: el pago no sale y nadie se entera. El cuarto es el único blando, y es el único que produce una pregunta.
total es el que importa y el que casi nunca está. No se renueva nunca: el
diario vuelve mañana, este no vuelve. Sin él, un agente puede gastar de a poco
para siempre —cada pago dentro del tope individual, cada día dentro del
diario— y no pasarse jamás de nada.
Por eso, cuando un pago choca contra varios topes a la vez, se reporta el total: decirle a alguien "te pasaste del diario" cuando en realidad agotó el presupuesto de por vida lo manda a esperar hasta mañana para chocarse contra la misma pared.
Y por eso conviene no llamarle cap al umbral de aprobación: suena a límite duro, y es el único que no lo es.
Tres cosas medidas que el agente te dice y WAD no
Lo que está entrando. wad_balance devuelve cero mientras un depósito
confirma — entre 14 y 17 minutos. En esa ventana un agente no distingue "no me
mandaron nada" de "me mandaron y está entrando". Con tu deposit address
configurada, preguntamos el saldo real a Base y lo mostramos aparte.
Cuánto se lleva la comisión. Cada liquidación arrastra ~0,004 USDC fijos de repago de gas, que no aparecen en ninguna respuesta. Al ser fija pesa 4% en un pago de 0,10 y 1,6% en uno de 0,25. El agente avisa antes, para que junte pagos en vez de hacer muchos chicos.
Lo que cuesta pedir permiso. Un pago auto-aprobado liquida en ~16 segundos; uno que pasa por aprobación humana tarda ~22 minutos. El umbral de aprobación no es solo una decisión de riesgo: también es de velocidad.
Desarrollo
npm install
npm test # 41 pruebas, sin red, sin gastar un centavo
npm run check # TypeScript en modo strictLa prueba contra el WAD real es aparte porque toca plata:
WAD_TOKEN=... node --import tsx/esm test/vivo.ts # no paga nada
WAD_TOKEN=... node --import tsx/esm test/vivo.ts --pagar # paga 0,01 USDCDecisiones de diseño
La plata es entera, siempre. Nada de coma flotante. Todo entra a minor units en el borde y no vuelve a salir. Un monto con más decimales de los que la moneda puede representar se rechaza en vez de redondearse.
El orden de las reglas importa. Primero lo que nunca se permite, después los topes duros, y recién al final la aprobación humana — así no se molesta a una persona pidiéndole que apruebe algo que igual iba a bloquearse.
Un reintento no gasta el tope dos veces. Si mandás la misma clave de idempotencia, se excluye del acumulado. Sin eso, reintentar un timeout consume presupuesto que nunca se gastó.
Una aprobación denegada es un fracaso, no un estado intermedio. Un pago que nadie aprobó es un pago que no se hizo.
MIT.
