SDK
Sessões, avisos e status: a API de status do Miblo
Cada método da API de status do Miblo: session, needsYou, done, say, focus, timer e snapshot, com parâmetros, respostas, erros e um exemplo completo.
O cliente
Tudo começa com um MibloStatus. Ele guarda o token e a porta e assina cada pedido; não abre conexão até o primeiro uso.
import { MibloStatus } from '@miblo/status';
const miblo = new MibloStatus({ token, port, timeoutMs }); // todos opcionaisfrom miblo_status import MibloStatus
miblo = MibloStatus(token=None, port=None, timeout=3.0) # todos opcionais| Parâmetro | Padrão | O que é |
|---|---|---|
token | MIBLO_TOKEN | O token de miblo sdk token. Sem ele, o construtor já lança no_token. |
port | MIBLO_PORT, senão 47821 | A porta da ponte. O endereço é sempre 127.0.0.1. |
timeoutMs / timeout | 3000 ms / 3.0 s | Quanto esperar cada resposta. |
hello()
Confere o token e a versão do Miblo, sem mudar nada: { api, version } (por exemplo { api: 1, version: "1.25.0" }). Útil para checar a instalação no início do programa.
const { api, version } = await miblo.hello();info = miblo.hello() # {"api": 1, "version": "1.25.0"}Como cada pedido é assinado
Você não precisa fazer nada disso, os pacotes fazem: antes de cada pedido o cliente pede um desafio (GET /sdk/v1/hello com um nonce aleatório), confere que a ponte provou conhecer o token, assina o pedido com HMAC-SHA256 (método, caminho e o SHA-256 do corpo) e, na volta, confere a assinatura da resposta. Um programa que ocupe a porta do Miblo enquanto ele está fora não consegue provar o token, e o cliente não manda nada a ele. O passo a passo está na referência.
Sessões
Uma sessão é o seu programa na lista do Miblo, ao lado das sessões das ferramentas de IA.
session()
const job = await miblo.session({ tool, title, cwd, state, detail, pid });job = miblo.session(tool, title=None, cwd=None, state="working", detail=None, pid=-1)| Campo | Obrigatório | Regras |
|---|---|---|
tool | sim | O nome do seu programa, 1 a 20 caracteres, uma linha. Não pode ser o nome de uma ferramenta do Claude Code (Bash, Edit, Read, Task, Agent...) nem começar com _. |
title | não | O nome da sessão no aparelho (até 64 caracteres; o aparelho mostra cerca de 20). Sem ele, vale a pasta de cwd; sem os dois, o tool. Nomes repetidos ganham " 2", " 3". |
cwd | não | Uma pasta; o nome dela vira o título quando não há title. |
state | não | working (padrão), needs_you, idle ou done. |
detail | não | Uma linha curta (até 64 caracteres; o que passar é cortado). É a atividade enquanto trabalha e o motivo quando precisa de você. |
pid | não | O processo cujo fim encerra a sessão. Padrão: o próprio programa. null (TS) ou None (Python): nenhum, e a sessão expira após 12 h sem atualização (2 h quando parada ou concluída). |
Devolve um objeto Session com id (sdk- + 32 hexadecimais, criado pela ponte) e state. Só ids sdk- são aceitos depois, então um programa nunca consegue mudar ou encerrar a sessão de uma ferramenta de IA.
Mudar o estado
| TypeScript | Python | Estado | No aparelho |
|---|---|---|---|
job.working(detail?) | job.working(detail=None) | working | A linha mostra tool · detail. |
job.needsYou(reason?) | job.needs_you(reason=None) | needs_you | Aviso de pergunta, uma vez por mudança; conta em "precisa de você". |
job.idle(detail?) | job.idle(detail=None) | idle | Parada, sem aviso. |
job.done(detail?) | job.done(detail=None) | done | Aviso de fim, uma vez por mudança. |
job.set(state, detail?) | job.set(state, detail=None) | qualquer um | O mesmo, escolhendo o estado. |
job.end() | job.end() | (sai) | Tira a sessão do Miblo: { id, ended: true }. |
Cada chamada devolve { id, state }. Os modos reunião e discreto escondem o detail, como fazem com toda sessão. As sessões sobrevivem a uma atualização da ponte, mas não a um reinício do computador.
Mensagens, foco e timer
As mesmas ações de miblo say, miblo focus e miblo timer, com os mesmos limites do aparelho.
| TypeScript | Python | Regras |
|---|---|---|
say(text, { minutes }) | say(text, minutes=None) | Uma linha, até 40 caracteres (47 bytes UTF-8), por 1 a 480 minutos (padrão 30). Não pode começar como os avisos do próprio Miblo ("Approved:", "Phone:", "Miblo:", "Allow?"... em inglês e português). |
sayOff() | say_off() | Tira a mensagem. |
focus({ focusMin, breakMin, rounds }) | focus(focus_min=None, break_min=None, rounds=None) | Foco de 5 a 120 min, pausa de 1 a 60, 1 a 12 rodadas. |
focusStop() | focus_stop() | Para o foco. |
timer(minutes) | timer(minutes) | 1 a 180 minutos. |
timerStop() | timer_stop() | Para o timer. |
Cada uma devolve { ok, delivered, gadgets }: delivered conta os aparelhos que aceitaram, e gadgets traz cada aparelho pareado com { id, name, ok, error? }, onde error é offline, unpaired, unsupported, rejected ou busy. Sem Miblo pareado, delivered é 0 e não é erro. Nada disso vira notificação no computador.
Snapshot
snapshot() lê quem está trabalhando e quem precisa de você, sem mudar nada.
const { sessions, gadgets } = await miblo.snapshot();
const waiting = sessions.filter((s) => s.state === 'needs_you');snap = miblo.snapshot()
waiting = [s for s in snap["sessions"] if s["state"] == "needs_you"]sessions:[{ id, name, state, tool, sdk, since }]. Uma sessão de ferramenta de IA aparece com um id de 8 caracteres e o nome da ferramenta emtool("Claude Code","Codex"...);sdkétruenas sessões de programas;sinceé o momento (epoch, em segundos) em que entrou no estado.gadgets:[{ id, name, online }].Nunca traz um comando, um arquivo, um prompt, um custo, um limite ou nada do Miblo+. Leituras: 5 por segundo, em rajadas de 10.
Exemplo completo
Um vigia de build: roda o comando, mostra o andamento, avisa quando falha e põe uma mensagem quando passa.
// 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: 'Build do site', 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('passou');
await miblo.say('Build verde', { minutes: 10 });
} else {
await job.needsYou(`falhou (saída ${code})`);
}
} catch (e) {
if (e instanceof MibloError && e.code === 'rate_limited') console.log(`tente em ${e.retryAfter} s`);
else throw e;
}# MIBLO_TOKEN=$(miblo sdk token) python3 build_watch.py
import subprocess
from miblo_status import MibloStatus, MibloError
miblo = MibloStatus()
job = miblo.session("build", title="Build do site", detail="npm run build")
code = subprocess.call(["npm", "run", "build"])
try:
if code == 0:
job.done("passou")
miblo.say("Build verde", minutes=10)
else:
job.needs_you(f"falhou (saída {code})")
except MibloError as e:
if e.code == "rate_limited":
print(f"tente em {e.retry_after} s")
else:
raiseErros
Todo erro é um MibloError com:
code: estável, nunca renomeado (lista abaixo);status: o status HTTP, ou0quando a ponte não foi alcançada;field(embad_request): o campo com problema, comotooloudetail;retryAfter(TS) /retry_after(Python) emrate_limited: quantos segundos esperar.
code | Status | Quando |
|---|---|---|
bad_request | 400 | Um campo fora da faixa ou do tipo errado (veja field) |
bad_json | 400 | O corpo não é JSON |
sdk_off | 401 | Sem token neste computador |
not_authorised | 401 | Token errado ou trocado |
unknown_session | 404 | A sessão terminou, expirou ou não é do SDK |
too_many_sessions | 409 | Já há 8 sessões do SDK |
too_large | 413 | Corpo acima de 4096 bytes (o cliente recusa antes de mandar) |
rate_limited | 429 | Acima de um limite; espere retryAfter segundos |
internal | 500 | Um bug do Miblo: conte para a gente |
Do lado do cliente: no_token, bridge_unavailable, timeout e unverified_answer (veja Instalação).
Chamadas de baixo nível
call(method, path, body?, opts?) faz um pedido assinado a qualquer rota /sdk/v1/* e devolve o JSON da resposta (lança MibloError em erro). Um Uint8Array (TS) ou bytes (Python) vai como application/octet-stream. Serve para rotas novas antes de o pacote ter um método para elas.
const screen = await miblo.call('GET', '/sdk/v1/screen', undefined, { tool: 'build' });screen = miblo.call("GET", "/sdk/v1/screen", tool="build")