RestRuno
Cliente REST de escritorio (Windows y macOS) — estilo Postman/Bruno, con colecciones 100 % locales, variables, scripts, runner con datos y generación de CSV.
Free y Pro
RestRuno es gratis para el trabajo diario: colecciones, peticiones, ambientes, variables, scripts con tests, import/export Postman/Bruno, cookies y consola. Dos funciones avanzadas forman parte de RestRuno Pro (pago único, licencia para 2 dispositivos):
| Free | Pro | |
|---|---|---|
| Colecciones, requests, ambientes, variables | ✔ | ✔ |
| Scripts pre/post con tests | ✔ | ✔ |
| Import/Export Postman y Bruno | ✔ | ✔ |
| ✨ Asistente de IA | — | ✔ |
| ▶ Runner data-driven (CSV/JSON, reportes, CSV de salida) | — | ✔ |
| 🔌 Servidor local MCP + API (control desde IA) | — | ✔ |
Comprar RestRuno Pro — $20 — pago único, actualizaciones incluidas, 2 dispositivos. La compra la procesa Polar y recibes tu license key por email; actívala en la app con el botón Upgrade de la barra superior. Términos de uso en la licencia (EULA).
¿Para tu equipo? RestRuno Enterprise — $149: pago único, 25 seats (una sola key para todo el equipo, 50 activaciones), rollout simple y soporte prioritario por email.
Instalación y actualizaciones
Instalar (los botones de restruno.com detectan tu sistema, o descarga del release más reciente):
- Windows:
restruno-X.Y.Z-setup.exe— instalador de un clic (Windows mostrará "editor desconocido" por ser una app sin firma: Más información → Ejecutar de todas formas). - macOS:
restruno-X.Y.Z-arm64.dmgpara Apple Silicon (chips M) orestruno-X.Y.Z-x64.dmgpara Macs Intel — abre el dmg y arrastra RestRuno a Aplicaciones.
Actualizaciones:
- Automáticas y silenciosas: poco después de abrir la app (cuando ya terminó de cargar, para no estorbar el arranque) se revisa este repositorio; si hay versión nueva se descarga completa en segundo plano.
- Cuando la descarga está lista aparece un botón naranja Update en la esquina inferior derecha: clic → se instala y la app se reinicia. Si no lo pulsas, la actualización se instala sola al cerrar la app.
- Buscar manualmente: haz clic en el número de versión (
vX.Y.Z) de la esquina inferior derecha. Te dice al momento si hay versión nueva (y arranca la descarga en segundo plano), si ya estás al día, o el error si no hay conexión. - Botón Docs (barra superior) abre esta documentación en tu navegador.
Colecciones
Una colección es una carpeta en tu disco que tú eliges. Cada petición es un archivo *.rr.json legible; las subcarpetas son folders. Puedes versionarlas con Git o respaldarlas copiando la carpeta.
| Acción | Cómo |
|---|---|
| Crear colección | Botón New → nombre → elige la carpeta padre |
| Abrir colección existente | Botón Open → selecciona la carpeta de la colección |
| Importar de Postman/Bruno | Botón Import → elige el JSON exportado (Postman v2.x o Bruno) |
| Exportar | Click derecho en la colección → Export Collection (genera Postman v2.1 + un archivo por ambiente) |
| Nueva petición / folder | Click derecho en la colección o folder → New Request / New Folder |
| Duplicar | Click derecho → Duplicate (peticiones, folders o la colección completa) |
| Renombrar / Eliminar | Click derecho → Rename / Delete |
| Mover | Arrastra y suelta peticiones o folders (con todo su contenido) a otro folder o a otra colección |
| Expandir / contraer todo | Botón ⊟/⊞ junto a Import |
| Ocultar panel lateral | Botón ◧ arriba a la izquierda o Ctrl+B |
Peticiones
- URL y Params sincronizados: agrega params en la pestaña Params y aparecen en la URL (y al revés, escribe
?a=1&b=2en la URL y se llena la tabla). - Auth: None, Bearer Token o Basic (acepta
{{variables}}). - Body: JSON, XML (SOAP), GraphQL (query + variables JSON), texto plano, form-url-encoded o multipart form (campos de texto y archivos). Selector de Content-Type visible, botón Beautify para JSON/XML, y el cURL exportado usa
-Fpara multipart. - Enviar: botón Send o Ctrl+Enter · Guardar: Save o Ctrl+S (el punto naranja en el tab indica cambios sin guardar).
- Copiar como cURL: botón cURL — copia el comando con todas las variables resueltas a su valor actual.
- Pegar un cURL: pega cualquier comando
curlen el campo de URL y se configuran método, URL, params, headers, auth y body automáticamente. - Response: status, tiempo, tamaño, fecha/hora y URL final (ambos ocultables con los botones ⏱ y URL), body con formato, headers, resultados de tests y consola. El panel puede ir abajo o al costado (botón ⬓/◨ en la barra superior).
Variables
Sintaxis {{variable}} en URL, params, headers, auth y body. Precedencia (mayor gana):
runtime (scripts) → fila del data file → colección → ambiente → globales
- Globales: botón Globals (aplican a todas las colecciones).
- De ambiente: selector arriba a la derecha; se administran en Manage Environments (por colección). Desde ahí también puedes copiar variables a otra colección (seleccionadas o todas).
- De colección: click derecho en la colección → Collection Variables.
Scripts (pestaña Scripts de cada petición)
Dos paneles: Pre Request (antes de enviar) y Post Response (validaciones). Cada panel tiene un menú Snippets… con ejemplos listos y un botón ⛶ para maximizarlo.
// Pre Request
rr.variables.set('token', 'abc'); // runtime: solo memoria, fluye entre peticiones
rr.variables.setGlobal('clave', 'valor'); // se guarda en globales (globals.json)
rr.variables.setEnvironment('token', 'abc'); // se guarda en el AMBIENTE ACTIVO (environments/<nombre>.json)
rr.request.headers['X-Trace'] = '1'; // modificar la petición saliente
// Post Response (tests)
rr.test('status es 200', () => rr.expect(rr.response.status).toBe(200));
rr.test('tiene id', () => rr.expect(rr.response.body.id).toBeDefined());
rr.variables.set('token', rr.response.body.token); // encadenar login → siguiente petición
Referencia de comandos rr
Los scripts son JavaScript síncrono en un sandbox. No hay require/import/fetch/process/setTimeout, ni async/await, ni acceso a red. Timeout de 5 segundos.
Variables (funcionan en pre y post):
| Comando | Qué hace | Persistencia |
|---|---|---|
rr.variables.get(key) |
Lee una variable resolviendo la precedencia: runtime → fila de datos → colección → ambiente → global | — |
rr.variables.set(key, value) |
Guarda en ámbito runtime (memoria); fluye a las siguientes peticiones de la sesión/run, se resetea entre iteraciones | No se guarda a disco |
rr.variables.setEnvironment(key, value) |
Guarda en el ambiente activo | environments/<nombre>.json (visible en el editor) |
rr.variables.setGlobal(key, value) |
Guarda una variable global | globals.json (diálogo Globals) |
Los valores se guardan como texto — usa
JSON.stringify(obj)si necesitas guardar un objeto, yJSON.parse(...)al leerlo.
Pre Request — modificar la petición antes de enviarla (solo en el script pre):
| Comando | Descripción |
|---|---|
rr.request.method |
Método (string), asignable |
rr.request.url |
URL (string, admite {{vars}}) |
rr.request.headers['Nombre'] = valor |
Agrega/reemplaza un header |
rr.request.params['clave'] = valor |
Agrega/reemplaza un query param |
Post Response — leer la respuesta (solo en el script post):
| Comando | Descripción |
|---|---|
rr.response.status |
Código HTTP (número), ej. 200 |
rr.response.statusText |
Texto del status |
rr.response.headers['content-type'] |
Headers (claves en minúscula) |
rr.response.body |
Body como JSON parseado (o undefined si no es JSON) |
rr.response.bodyText |
Body como texto crudo |
rr.response.timeMs |
Tiempo transcurrido (número) |
rr.response.sizeBytes |
Tamaño de la respuesta (número) |
Tests (post) — cada rr.test se reporta como pass/fail en el runner y el panel de respuesta:
rr.test('nombre', () => { ... })rr.expect(actual)con matchers:.toBe(x)(=== estricto),.toEqual(x)(comparación profunda),.toContain(x)(item de array o substring),.toBeDefined(),.toBeLessThan(n),.toBeGreaterThan(n),.toMatch(regexOStr), y el prefijo de negación.not(ej.rr.expect(s).not.toBe(500)).
console.log/info/warn/error(...) se captura y aparece en la consola global.
Ejemplo completo (post-response de un login que guarda el token de forma persistente):
rr.test('login OK', () => rr.expect(rr.response.status).toBe(200));
rr.test('devuelve token', () => rr.expect(rr.response.body.access_token).toBeDefined());
rr.test('content-type json', () =>
rr.expect(rr.response.headers['content-type']).toMatch(/application\/json/));
// guarda el token en el ambiente activo para las siguientes peticiones:
rr.variables.setEnvironment('token', rr.response.body.access_token);
console.log('token guardado:', rr.response.body.access_token);
El menú Snippets… de cada panel inserta muchos de estos patrones listos para usar. Si tienes el asistente de IA activado, el botón ✨ genera scripts a partir de una descripción usando esta misma referencia.
Runner (Pro)
Función de RestRuno Pro desde la versión 3.0.
Click derecho en una colección o folder → Run Collection / Run Folder. Se abre como un tab de pantalla completa:
- Dos vistas (botón ⬓/◨ del runner): apilada, o dividida con la configuración a la izquierda y las ejecuciones a la derecha. Mientras el run está en curso, la configuración se oculta para dar todo el espacio a los resultados.
- Selección de peticiones: checkboxes para ejecutar solo un subconjunto. La selección se conserva entre ejecuciones del mismo scope — puedes correr, ajustar y repetir sin re-marcar.
- Data file (CSV / JSON / TXT): repite la secuencia una vez por fila; cada columna se vuelve una
{{variable}}(TXT usa la variablevalue). - Iterations: campo junto al Run — cuántas iteraciones ejecutar. El máximo es la cantidad de filas del data file (sin archivo, siempre 1).
- Resultados con detalle completo: expande cualquier ejecución para ver sus tests, la consola, y los bloques Request (método, URL resuelta, headers, body enviado) y Response (status, headers, body). Los bodies muy grandes se recortan en pantalla; con Persist tienes la copia completa.
- Persistir ejecuciones: checkbox que guarda el request resuelto + response completo de cada ejecución en
runs/dentro de la colección. - Generar CSV (sección contraíble ▸): activa Generate CSV file from response values, elige carpeta y nombre, y define columnas con expresiones sobre el response:
body.data[0].id,status,headers.content-type,timeMs,request.url,iteration. Cada columna puede sertext(valor tal cual) onumber(elimina ceros a la izquierda:00742→742). El selector Save always / Only passed / Only failed controla qué ejecuciones escriben fila — y en todos los casos, solo se escribe la fila si al menos una expresión hace match. - Los fallos no detienen el run; puedes cancelar en cualquier momento.
Asistente de IA (Pro)
Función de RestRuno Pro desde la versión 3.0. La configuración es libre; ejecutar acciones de IA requiere licencia.
Botón ✨ AI en la barra superior. Conecta cualquier endpoint compatible con OpenAI: OpenAI, Ollama, LM Studio, OpenRouter, Groq, etc. Es totalmente opcional — si no lo configuras, RestRuno funciona exactamente igual y no aparece ningún botón de IA.
💡 Funciona con modelos open source — gratis y 100 % en tu máquina. Instala Ollama o LM Studio y usa Llama, Mistral, DeepSeek, Qwen, Gemma, o cualquier otro modelo abierto, corriendo localmente: sin pagar ninguna API, sin suscripciones y sin que tus requests salgan de tu computadora. También puedes usar modelos open source alojados (OpenRouter, Groq) si prefieres no correrlos tú.
Configuración (se guarda solo en tu computadora):
| Campo | Ejemplos |
|---|---|
| Base URL | https://api.openai.com/v1 · http://localhost:11434/v1 (Ollama) · https://openrouter.ai/api/v1 |
| API Key | tu clave del proveedor (vacío para modelos locales) |
| Model | gpt-4o-mini · llama3.1 · claude-3-5-sonnet … |
Marca Enable AI assistant, usa Test Connection para verificar, y guarda. El botón ✨ AI de la barra superior muestra un punto verde cuando está habilitado y el último test de conexión fue exitoso (gris si está deshabilitado o sin verificar). Al habilitarlo aparecen botones ✨ en tres lugares:
- Scripts (pre y post) — ✨ en el encabezado de cada panel: describe lo que necesitas ("valida que el status sea 201 y guarda el id en una variable") y genera el script usando la API
rr.*correcta, con el contexto de tu request. Botón Insert into script lo agrega al editor. - Response — botón ✨ Explain: analiza el request + response + tests fallidos y te explica qué pasó, la causa probable del error y cómo corregirlo.
- Columnas CSV del Runner — ✨ AI expression: describe el valor que quieres extraer ("el id del primer item") y genera la expresión (
body.items[0].id) usando como contexto el último response del run; Add as column la agrega directo.
En cada acción puedes editar la instrucción, regenerar, copiar o insertar el resultado. Privacidad: al usar estas acciones, el request/response involucrado se envía a tu proveedor de IA configurado — con Ollama/LM Studio todo queda en tu máquina.
Ejemplos de uso:
- Scripts: "valida que el status sea 201, que el body tenga
idnumérico, y guardaaccess_tokenen el ambiente activo" → genera el post-response conrr.test,rr.expectyrr.variables.setEnvironmentlistos para insertar. - Explain: ante un 500 inesperado, ✨ Explain te dice qué salió mal (header faltante, body mal formado, error del servidor) y qué corregir.
- Runner CSV: "el email del segundo usuario de la lista" → genera
body.users[1].emaily la agrega como columna.
Consola global
Barra Console al pie de la ventana: registra cada petición enviada, cada ejecución del runner y los console.log de tus scripts. Filtros All / Requests / Errors / Logs, fecha y hora ocultable, y botón Clear.
Servidor local MCP + API (Pro)
Función de RestRuno Pro desde la versión 3.0.
Botón MCP Server en la barra superior. Permite que una IA (Claude, GitHub Copilot, Cursor, Antigravity, OpenAI Codex, etc.) controle RestRuno: crear, editar, eliminar y enviar requests, y leer el response, la consola y los errores — todo local, sin nube.
- 100% local: escucha solo en
127.0.0.1(nunca accesible desde fuera de tu equipo). Desactivado por defecto. - Punto de estado: el botón MCP Server muestra un punto verde cuando el servidor está encendido y gris cuando está apagado.
- Token bearer: cada petición externa debe presentar el token que se muestra en la ventana (puedes regenerarlo). Cópialo con un click.
- El servidor solo actúa sobre las colecciones que tienes abiertas en la app; no puede leer ni escribir archivos fuera de ellas.
Cómo configurarlo
- Abre MCP Server → marca Enable local server (aparece "● running").
- Copia el MCP endpoint (
http://127.0.0.1:<puerto>/mcp) y el Bearer token. - En Connect your AI — pick your client, elige tu cliente y copia el snippet listo para pegar:
| Cliente | Dónde va la configuración |
|---|---|
| Claude Code | Un comando en la terminal: claude mcp add --transport http restruno <url> --header "Authorization: Bearer <token>" |
| Claude Desktop | Settings → Developer → Edit Config → claude_desktop_config.json (usa el puente mcp-remote); reinicia Claude |
| VS Code / Copilot | .vscode/mcp.json del proyecto (agent mode de Copilot) |
| OpenAI Codex | Un comando en la terminal: codex mcp add restruno -- npx -y mcp-remote <url> --header "Authorization: Bearer <token>" |
| Cursor / Antigravity / otros | JSON genérico mcpServers — ~/.cursor/mcp.json en Cursor, panel de MCP (mcp_config.json) en Antigravity; la mayoría de clientes MCP aceptan esta misma forma |
Herramientas expuestas al cliente MCP: list_collections, get_tree, read_request, create_request, update_request, delete_request, create_folder, send_request, get_console.
Ejemplos de uso (desde tu IA)
Con el cliente conectado, pídele cosas como:
- "Lista mis colecciones de RestRuno y muéstrame el árbol de la colección
pagos." - "Crea en
pagosun request POST a{{baseUrl}}/refundscon este body JSON y envíalo; dime el status y el body de respuesta." - "Envía el request
login, y con lo que veas en la consola dime por qué está fallando." - "Recorre todos los requests del folder
smokey márcame cuáles no devuelven 200."
API REST (alternativa sin MCP)
Llamadas HTTP planas a http://127.0.0.1:<puerto>/api/* con Authorization: Bearer <token> — útil para scripts o CI local:
# listar colecciones (devuelve name + rootPath de cada una)
curl http://127.0.0.1:<puerto>/api/collections -H "Authorization: Bearer <token>"
# árbol de una colección
curl "http://127.0.0.1:<puerto>/api/tree?rootPath=/ruta/a/pagos" -H "Authorization: Bearer <token>"
# enviar un request existente (ruta absoluta) con un ambiente, y leer el response
curl -X POST http://127.0.0.1:<puerto>/api/send \
-H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
-d '{"requestPath": "/ruta/a/pagos/login.rr.json", "environmentName": "dev"}'
# leer la consola (últimas 20 entradas)
curl "http://127.0.0.1:<puerto>/api/console?limit=20" -H "Authorization: Bearer <token>"
Endpoints: GET /api/health · GET /api/collections · GET /api/tree?rootPath= · GET|POST|PATCH|DELETE /api/request · POST /api/folder · POST /api/send · GET /api/console?limit=.
Cookies de sesión
Las respuestas con Set-Cookie se recuerdan solo en memoria (nunca en disco) y se reenvían a peticiones del mismo host — así funcionan los flujos de login. En Globals puedes desactivarlas o limpiarlas. No se almacena caché HTTP.
¿Dónde se guarda todo?
| Qué | Dónde |
|---|---|
| Peticiones, folders, variables de colección | La carpeta de la colección (archivos JSON) |
| Ambientes | environments/ dentro de la colección |
| Ejecuciones persistidas del runner | runs/ dentro de la colección |
| Variables globales y preferencias | Perfil del usuario (AppData) |
| Responses de peticiones manuales | Solo en memoria (se pierden al cerrar) |
| Cookies | Solo en memoria (se pierden al cerrar) |
Atajos
Ctrl+Enter enviar · Ctrl+S guardar · Ctrl+W cerrar tab · Ctrl+B mostrar/ocultar panel lateral