Documentação / Cards

Terminal e providers

Cada card de terminal é um processo real de um provider — Claude, Codex, Cursor, Antigravity, OpenCode, Cline, Command Code ou um shell puro.

Cada card de terminal é um PTY de verdade, rodando um provider ou um shell puro. O Stellar não simula terminal: o que aparece no card é o processo.

Providers

Provider O que roda
claude Claude Code
codex Codex
cursor Cursor
antigravity Antigravity (Gemini)
opencode OpenCode
cline Cline
commandcode Command Code
bash um shell, sem agente por trás

Os últimos dois não são código: são dado. O catálogo embutido declara binário, como o id de sessão entra, qual flag carrega prompt de sistema, onde fica o config de MCP, esforço e modelo — e os argumentos são sintetizados a partir dessa declaração. É o que permite declarar os seus: um providers.json na pasta de configuração registra um CLI novo sem reiniciar o app (ver Onde ficam os dados).

O provider se escolhe na criação do card. Ele não é herdado de quem despachou: uma task que não declara provider é recusada, de propósito — prender a cadeia inteira no provider de quem começou seria uma decisão silenciosa demais.

Instalado não é pronto

O binário resolver no PATH responde uma pergunta só. A disponibilidade tem quatro respostas, e cada uma é do tamanho da prova que a sustenta:

Resposta O que sustenta
missing o binário não resolve no PATH
not-ready instalado, e o probe declarado respondeu que não está pronto (credencial faltando, por exemplo)
ready instalado, e o probe respondeu que está
unknown instalado, e o app não sabe — nenhum probe foi declarado, ou ele não chegou a responder

unknown é o default de um provider que não declara nada, e nunca vira “pronto” por otimismo. O caso que forçou isso está medido: um CLI instalado e sem credencial aparecia como disponível, o spawn “dava certo” e o card ficava calado para sempre. O probe mora na declaração do provider porque “pronto” varia por harness — e o que o app lê é o campo que o próprio tool imprime, não o exit code.

Zoom sem reflow

O zoom do canvas é ótico: o texto escala como imagem, sem disparar fit() nem reflow de colunas e linhas no meio da sessão. O PTY só é redimensionado quando você arrasta a borda física do card.

Sessão e retomada

Todo card pode ser retomado com o id de sessão do provider, mas não do mesmo jeito — e a diferença que importa é entre impor e retomar.

Impor é criar a sessão já com o id escolhido pelo Stellar. Só dois providers sabem: claude, com --session-id, e cursor, com --new-session-id. No cursor a flag de impor não aparece no --help, e por um tempo o app usou --resume para os dois papéis — que pedia para retomar uma sessão que ainda não existia.

Retomar é apontar para uma sessão que já existe, descoberta no store do provider: cline (--id), codex (resume <id> — um subcomando, não uma flag), opencode (--session), commandcode (--resume) e antigravity (--conversation). Nenhum desses aceita um id desconhecido: um id imposto seria ignorado em silêncio.

O registro guarda dois ids distintos: o resumeId pedido no spawn e o sessionId descoberto em runtime. Quando o provider impõe um id diferente do pedido, é o segundo que vale.

E a imposição é conferida, não presumida. Depois do spawn, o app lê o store declarado pelo provider e procura o id imposto ali. Se não achar, a declaração foi contradita por medição e o watcher de sessão volta a valer — em vez de o card apontar para sempre para uma sessão que não existe. A checagem existe porque canImposeSessionId: true é uma afirmação num arquivo de configuração, e nada a conferia: foi assim que o defeito do cline (a flag era de retomar) e o do cursor (a flag estava errada) passaram.

Onde não há nem imposição nem sessão descobrível, o registro fica ausente, honestamente, em vez de inventar um id.

Cota e morte de agente

Providers morrem por cota no meio do trabalho. Antes de concluir que o agente falhou, leia o scrollback do card: morte por cota se parece com morte por bug quando ninguém olha.