Saltar al contenido
miblo

SDK

Sesiones, alertas y estado: la Status API de Miblo

Cada método de la Status API de Miblo: session, needsYou, done, say, focus, timer y snapshot, con parámetros, respuestas, errores y un ejemplo completo.

El cliente

Todo empieza con un MibloStatus. Guarda el token y el puerto y firma cada solicitud; no abre ninguna conexión hasta que se usa por primera vez.

import { MibloStatus } from '@miblo/status';

const miblo = new MibloStatus({ token, port, timeoutMs });   // all optional
ParámetroPor defectoQué es
tokenMIBLO_TOKENEl token de miblo sdk token. Sin él, el constructor lanza no_token de inmediato.
portMIBLO_PORT, si no 47821El puerto del puente. La dirección siempre es 127.0.0.1.
timeoutMs / timeout3000 ms / 3.0 sCuánto esperar cada respuesta.

hello()

Verifica el token y la versión de Miblo sin cambiar nada: { api, version } (por ejemplo { api: 2, version: "1.37.0" }: api es la API del SDK que habla el puente). Útil para comprobar la configuración cuando tu programa arranca.

const { api, version } = await miblo.hello();

Cómo se firma cada solicitud

Tú no haces nada de esto, lo hacen los paquetes: antes de cada solicitud el cliente pide un desafío (GET /sdk/v1/hello con un nonce aleatorio), verifica que el puente demostró conocer el token y que las versiones coinciden (upgrade, bridge_outdated), firma la solicitud con HMAC-SHA256 (método, ruta y el SHA-256 del cuerpo) y, a la vuelta, verifica la firma de la respuesta. Un programa que toma el puerto de Miblo mientras Miblo está caído no puede demostrar el token, y el cliente no le envía nada. El paso a paso está en la referencia.

Sesiones

Una sesión es tu programa en la lista de Miblo, junto a las sesiones de las herramientas de IA.

session()

const job = await miblo.session({ tool, title, cwd, state, detail, pid });
CampoObligatorioReglas
toolsíEl nombre de tu programa, de 1 a 20 caracteres, en una línea. No puede ser el nombre de una herramienta de Claude Code (Bash, Edit, Read, Task, Agent...) ni empezar con _.
titlenoEl nombre de la sesión en el Miblo Desk (hasta 64 caracteres; el Miblo Desk muestra unos 20). Sin él, lo nombra la carpeta de cwd; sin ninguno de los dos, tool. Los nombres repetidos reciben " 2", " 3".
cwdnoUna carpeta; su nombre pasa a ser el título cuando no hay title.
statenoworking (por defecto), needs_you, idle o done.
detailnoUna línea corta (hasta 64 caracteres; si es más larga, se corta). Es la actividad mientras trabaja y el motivo mientras te necesita.
pidnoEl proceso cuya salida termina la sesión. Por defecto: tu propio programa. null (TS) o None (Python): ninguno, y la sesión expira tras 12 h sin una actualización (2 h una vez en reposo o terminada).

Devuelve una Session con id (sdk- + 32 caracteres hexadecimales, hecho por el puente) y state. Después solo se aceptan ids sdk-, así que un programa nunca puede cambiar ni terminar la sesión de una herramienta de IA.

Cambiar el estado

TypeScriptPythonEstadoEn el Miblo Desk
job.working(detail?)job.working(detail=None)workingLa línea dice tool · detail.
job.needsYou(reason?)job.needs_you(reason=None)needs_youLa alerta de pregunta, una vez por cambio; cuenta en "te necesita".
job.idle(detail?)job.idle(detail=None)idleEn reposo, sin alerta.
job.done(detail?)job.done(detail=None)doneLa alerta de terminado, una vez por cambio.
job.set(state, detail?)job.set(state, detail=None)cualquieraLo mismo, eligiendo el estado.
job.end()job.end()(desaparece)Saca la sesión de Miblo: { id, ended: true }.

Cada llamada devuelve { id, state }. Los modos reunión y discreto ocultan el detail, como hacen con toda sesión. Las sesiones sobreviven a una actualización del puente, pero no a un reinicio del computador.

Mensajes, enfoque y temporizador

Las mismas acciones que miblo say, miblo focus y miblo timer, con los límites propios del Miblo Desk.

TypeScriptPythonReglas
say(text, { minutes })say(text, minutes=None)Una línea, hasta 40 caracteres (47 bytes UTF-8), de 1 a 480 minutos (por defecto 30). No puede empezar como los avisos propios de Miblo ("Approved:", "Phone:", "Miblo:", "Allow?"... en inglés y portugués).
sayOff()say_off()Quita el mensaje.
focus({ focusMin, breakMin, rounds })focus(focus_min=None, break_min=None, rounds=None)Enfoque de 5 a 120 min, descanso de 1 a 60, de 1 a 12 rondas.
focusStop()focus_stop()Detiene la sesión de enfoque.
timer(minutes)timer(minutes)De 1 a 180 minutos.
timerStop()timer_stop()Detiene el temporizador.

Cada una devuelve { ok, delivered, gadgets }: delivered cuenta los dispositivos que lo recibieron, y gadgets lista cada dispositivo emparejado como { id, name, ok, error? }, donde error es offline, unpaired, unsupported, rejected o busy (un Miblo Desk con un firmware anterior a 1.30.0 no se maneja y aparece como offline: actualízalo). Sin ningún Miblo emparejado, delivered es 0, que no es un error. Nada de esto se convierte en una notificación de escritorio.

Snapshot

snapshot() lee quién está trabajando y quién te necesita, sin cambiar nada.

const { sessions, gadgets } = await miblo.snapshot();
const waiting = sessions.filter((s) => s.state === 'needs_you');
  • sessions: [{ id, name, state, tool, sdk, since }]. La sesión de una herramienta de IA aparece con un id de 8 caracteres y el nombre de la herramienta en tool ("Claude Code", "Codex"...); sdk es true para las sesiones de programas; since es cuándo entró en su estado (segundos epoch).

  • gadgets: [{ id, name, online }].

  • Nunca lleva un comando, un archivo, un prompt, un costo, un límite ni nada de Miblo+. Lecturas: 5 por segundo, ráfagas de 10.

Ejemplo completo

Un vigilante de builds: ejecuta el comando, muestra su progreso, te avisa cuando falla y pone un mensaje cuando pasa.

// MIBLO_TOKEN=$(miblo sdk token) node build-watch.mjs
import { spawn } from 'node:child_process';
import { MibloStatus, MibloError } from '@miblo/status';

const miblo = new MibloStatus();
const job = await miblo.session({ tool: 'build', title: 'Site build', detail: 'npm run build' });

const code = await new Promise((resolve) => {
  spawn('npm', ['run', 'build'], { stdio: 'inherit' }).on('exit', resolve);
});

try {
  if (code === 0) {
    await job.done('passed');
    await miblo.say('Build green', { minutes: 10 });
  } else {
    await job.needsYou(`failed (exit ${code})`);
  }
} catch (e) {
  if (e instanceof MibloError && e.code === 'rate_limited') console.log(`try again in ${e.retryAfter} s`);
  else throw e;
}

Errores

Cada error es un MibloError con:

  • code: estable, nunca se renombra (lista abajo);

  • status: el estado HTTP, o 0 cuando no se llegó al puente;

  • field (en bad_request): el campo con el problema, como tool o detail;

  • retryAfter (TS) / retry_after (Python) en rate_limited: cuántos segundos esperar.

codeEstadoCuándo
bad_request400Un campo fuera de rango o del tipo equivocado (ver field)
bad_json400El cuerpo no es JSON
sdk_off401No hay token en este computador
not_authorised401Token incorrecto o rotado
unknown_session404La sesión terminó, expiró o no es una sesión del SDK
not_found404No existe esa ruta (con call())
method_not_allowed405El método equivocado para la ruta (con call())
too_many_sessions409Hay 8 sesiones del SDK activas
too_large413Cuerpo de más de 4096 bytes (el cliente lo rechaza antes de enviarlo)
upgrade426Este SDK es más antiguo de lo que Miblo acepta: instala el SDK 2.x
rate_limited429Se superó un límite; espera retryAfter segundos
internal500Un bug en Miblo: avísanos, por favor
busy503El puente está ocupado con el mismo tipo de solicitud; espera retryAfter segundos

Del lado del cliente: no_token, bridge_unavailable, timeout, unverified_answer y bridge_outdated (ver Instalación). Las páginas de la pantalla, las apps y las alertas listan sus propios códigos.

Llamadas de bajo nivel

call(method, path, body?, opts?) hace una solicitud firmada a cualquier ruta /sdk/v1/* y devuelve el JSON de la respuesta (lanza MibloError ante un error). Un Uint8Array (TS) o bytes (Python) va como application/octet-stream. Úsalo para rutas nuevas antes de que el paquete tenga un método para ellas. Opciones: { tool, timeoutMs } (TS) / tool=, timeout= (Python); tool es el nombre de tu programa, que las rutas de pantalla y de apps necesitan.

const screen = await miblo.call('GET', '/sdk/v1/screen', undefined, { tool: 'build' });