Manual de Operação do Desktop AgentOS (genérico para qualquer agente)
Este manual é autocontido: contanto que seu framework consiga montar servidores MCP stdio (goose / Claude Code / Z Code / Cursor etc.), sigam a §1 para montar e obter todas as capacidades abaixo. Todos os itens foram testados em hardware real (Fedora + niri Wayland, evidenciados de ponta a ponta em 2026-10 no repositório docs/capabilities.md).
0. Modelo Mental: Quatro Camadas de Capacidade, em Ordem Decrescente de Prioridade
- L0 – Camada de Sistema — janelas / workspaces / inicialização / arquivos / notificações / área de transferência (extensões niri/desktop/system/files): a mais estável, use primeiro;
- L1 – Árvore de Acessibilidade — clicar por nome e ler/escrever texto dentro de aplicativos GUI (extensão a11y, AT-SPI2): não requer foco, não incomoda o usuário, testado em GTK3/GTK4/Qt (a chave global do Qt e o toolkit-accessibility do Chromium já são padrão do sistema desde 2026-10-18); leitura de árvore e entrada de texto no Chromium são possíveis (cliques em página vão para L2); Java não instalado (caminho no apêndice B do capabilities.md); aplicativos puramente X11 (classe xterm) não têm árvore, só L3;
- L2 – CDP do Navegador — todas as operações em páginas web (extensão browser, Chromium headless dedicado ao agente);
- L3 – Fallback Visual/Entrada — screenshot (grim, confiável), injeção de teclado (
scripts/kb-inject.sh: wtype a nível de usuário como principal, texto/combinações de teclas confiáveis; teclas de controle (Enter/Tab) caem para ydotool que requer sudo), injeção de ponteiro (não confiável: desvia com aceleração, apenas como último recurso).
Ao encontrar um aplicativo que "não abre/não funciona bem": primeiro pense se as pré-condições L1 não foram atendidas (chave a11y), depois use L3 com screenshot para ver o estado real, não tente repetir cegamente.
1. Montagem (única vez)
goose (~/.config/goose/config.yaml, formato testado na versão 1.54; o campo name: é obrigatório, sem ele a extensão inteira é descartada silenciosamente):
extensions:
niri:
type: stdio
name: niri
enabled: true
cmd: /path/to/AgentOS/scripts/env/with-niri-env.sh
args: []
env_keys: []
envs: {}
timeout: 300 # unidade: segundos
# desktop/system/files/session/a11y/browser/cred são isomórficos,
# cmd usa com with-desktop-env.sh / with-system-env.sh / ... (oito lançadores em scripts/env/)
Outros frameworks (Claude Code / Z Code etc. estilo JSON mcpServers):
{
"mcpServers": {
"niri": { "command": "/path/to/AgentOS/scripts/env/with-niri-env.sh" },
"desktop": { "command": "/path/to/AgentOS/scripts/env/with-desktop-env.sh" },
"system": { "command": "/path/to/AgentOS/scripts/env/with-system-env.sh" },
"files": { "command": "/path/to/AgentOS/scripts/env/with-files-env.sh" },
"session": { "command": "/path/to/AgentOS/scripts/env/with-session-env.sh" },
"a11y": { "command": "/path/to/AgentOS/scripts/env/with-atspi-env.sh" },
"browser": { "command": "/path/to/AgentOS/scripts/env/with-browser-env.sh" },
"cred": { "command": "/path/to/AgentOS/scripts/env/with-cred-env.sh" }
}
}
Pontos importantes:
- Use os scripts lançadores, não aponte diretamente para node dist/index.js — o lançador descobre o socket IPC do niri
(caminho contém o PID do compositor, diferente a cada sessão, ex.:
/run/user/1000/niri.wayland-1.2762.sock) e completa o ambiente Wayland/dbus (XDG_RUNTIME_DIR/WAYLAND_DISPLAY/DBUS_SESSION_BUS_ADDRESS), para que a ferramenta funcione quando iniciada a partir de SSH/ambiente de serviço; - Teste manual do lançador:
timeout 2 scripts/env/with-niri-env.sh </dev/null, exit 0 significa OK; - Pré-requisitos: Node ≥ 20, repositório com
npm install && npm run buildjá executado, executar sob o mesmo usuário da sessão gráfica niri.
2. Referência Rápida de Ferramentas (agrupadas por extensão, nome da ferramenta = <extensão>__<ferramenta>)
niri —— Janelas / Workspaces / Inicialização (L0)
| Ferramenta | Uso | Parâmetros Chave |
|---|---|---|
list_windows | Lista todas as janelas (id/app_id/título/workspace/foco) | — |
list_workspaces | Lista workspaces (idx numérico é diferente de id; para mover use número ou nome) | — |
list_outputs | Lista monitores | — |
focus_window | Muda o foco para a janela (muda a perspectiva do usuário, use com cautela) | id |
focus_workspace | Muda de workspace (muda a perspectiva do usuário) | reference: "3" ou nome |
move_window_to_workspace | Move janela (não rouba o foco, para organizar) | id? (padrão = janela em foco), reference |
close_window | Fecha janela | id? |
open_app | Inicia um programa no desktop do usuário | command: array, ex.: ["ghostty"] |
a11y —— Operações dentro de aplicativos GUI (L1, AT-SPI2)
| Ferramenta | Uso | Parâmetros Chave |
|---|---|---|
a11y_list_apps | Lista aplicativos registrados no barramento de acessibilidade | — |
a11y_dump_tree | Despeja a árvore de acessibilidade de um aplicativo (encontre nomes de botões / estrutura) | app |
a11y_click | Clica pelo nome acessível (não requer foco, não incomoda o usuário) | app, buttonName |
a11y_read_texts | Lê todos os textos não vazios de um aplicativo (tela / resultados / rótulos) | app |
a11y_set_text | Escreve em um campo de texto pelo nome do nó | app, match (substring do nome, padrão * primeiro), text |
Disciplina comprovada: enderece por nome, não por índice da árvore (a estrutura da árvore é reconstruída ao reconectar o AT); árvores do GTK4 só ficam completas após o registro do cliente AT; instâncias múltiplas com o mesmo nome – a ponte resolve para a primeira registrada – leia o texto para distinguir o estado da instância, feche as extras se necessário. Exceção do Chromium: árvore construída lentamente (a ponte a aciona automaticamente, primeiro dump pode levar 1-2 segundos extras – normal); escrever em campos de texto use combinação grabFocus + kb-inject type (o entry do Chromium não aceita setTextContents); cliques em botões de página não funcionam (doAction é despachado mas onclick não executa), operações em página vão sempre pela extensão browser.
browser —— Operações em Páginas Web (L2, Chromium headless dedicado ao agente)
| Ferramenta | Uso | Parâmetros Chave |
|---|---|---|
browser_open | Navega (primeira chamada inicia o navegador automaticamente) | url |
browser_eval | Executa JS na página, preenche formulários / clica / lê conteúdo – tudo por ela | Código JS |
browser_screenshot | Screenshot (navegador headless, visual depende totalmente dele) | — |
Ação padrão para preencher formulários: após el.value = "..." é obrigatório el.dispatchEvent(new Event("input", {bubbles: true})),
caso contrário frameworks modernos não recebem a entrada. Ao encontrar CAPTCHA: pare e informe o usuário, nunca contorne automaticamente.
files —— Sandbox de Arquivos (L0, raiz = ~/Agent/, caminhos sempre relativos)
| Ferramenta | Uso | Parâmetros Chave |
|---|---|---|
read_file / write_file | Lê / escreve texto (cria diretório pai automaticamente) | path, content |
list_dir / create_dir | Lista / cria diretório | path |
move / delete | Move / deleta (vai para .trash, recuperável, não use shell rm) | source/dest, path |
find_by_name | Encontra arquivos por nome | pattern |
download | Download http(s) para dentro da sandbox (≤50MB / 60s, não use shell curl) | url, path |
desktop —— Apresentação / Notificações / Área de Transferência / Confirmação (L0)
| Ferramenta | Uso | Parâmetros Chave |
|---|---|---|
open | Abre artefato: URL ou arquivo; documentos office devem usar app: "libreoffice" (lista branca, associação MIME do sistema não é confiável) | target, app? |
notify | Notificação no desktop (três níveis, veja §3) | summary (obrigatório), body, urgency, action? |
confirm | Pede autorização/decisão ao usuário (T1: quatro banners: permitir / permitir na sessão / negar / nunca; 30s sem resposta = negar) | summary (sem conteúdo sensível), tier? (t1/t2, afeta o texto) |
clipboard_read / clipboard_write | Lê / escreve na área de transferência | — |
session —— Aquário (sessão niri aninhada dedicada ao agente, toda ação GUI ocorre aqui)
| Ferramenta | Uso |
|---|---|
agent_session_start / agent_session_stop / agent_session_status | Ciclo de vida da sessão aninhada (aparece uma janela observável no desktop) |
agent_open_app | Inicia aplicativo dentro do aquário (ex.: gnome-calculator, chromium) |
agent_list_windows | Lista janelas dentro do aquário |
agent_screenshot | Screenshot direcionado do interior do aquário (grim) |
system —— Consultas ao Sistema (L0, somente leitura, tudo liberado)
system_status / list_services / service_status / journal / network_info /
list_packages / package_info / package_install (T2 confirmação forte: abre janela de senha polkit, requer presença humana;
se headless, timeout de 300s e recusa – não chame em modo não supervisionado).
cred —— Credenciais (agente recebe referência, não texto claro)
cred_list (credenciais disponíveis e suas referências/nomes de env var) · cred_autofill (canal A: preenchimento automático na página, texto claro descartado) ·
cred_exec (canal B: execução delegada em lista branca + saída mascarada) · cred_inject (canal C: injeção de variáveis de ambiente com TTL curto, toda a série removida ao expirar).
Qualquer operação que precise de senha/token deve usar apenas cred, nunca peça texto claro ao usuário.
3. Convenções Comportamentais (disciplina comprovada em testes)
- Artefatos sempre caem em
~/Agent/, categorizados emdownloads/ inbox/ reports/ notes/ canvas/ screenshots/; a queda já entra automaticamente no índice de artefatos (http://127.0.0.1:7788/artifacts); se o usuário perguntar "onde está meu relatório da última vez" → abra essa página ou informe o caminho relativo; - Prioridade de apresentação: dashboard / relatório / conteúdo interativo → escreva HTML autocontido em
canvas/<nome>/index.htmle depoisopenpara abrirhttp://127.0.0.1:7788/<nome>/; documentos office →opencomapp: "libreoffice"; páginas web → extensão browser; - Três níveis de notificação: conclusão →
notifycom urgency=low + action ({kind:"open_path", path:"reports/x.fodt"}ou{kind:"open_url", url:...}, clicar na notificação leva direto ao artefato); falha / precisa saber rápido → urgency=critical + conclusão em uma frase + causa e sugestão; quando precisa de decisão do usuário → não use notify, useconfirm(notify não tem semântica de escolha). Resultados assíncronos sempre notificam, nunca concluir silenciosamente; - Confirmação e bom senso: não mexa na janela que o usuário está usando, a menos que explicitamente solicitado (primeiro
list_windowspara identificar o alvo); quando houver recusa por política (isError e mensagem "recusa por política"), informe honestamente, não tente contornar; operações GUI faz no aquário, não roube o foco do usuário; - Credenciais apenas via referência cred-mcp (a disciplina após a tabela cred na §2).
4. Referência Rápida de Armadilhas do Ambiente (todas já enfrentadas)
| Armadilha | Fenômeno | Ação |
|---|---|---|
| Caminho do socket IPC do niri muda a cada sessão | niri msg não conecta | Use o lançador (descobre automaticamente NIRI_SOCKET), nunca hardcode |
| Chaveiro do Chromium trava serviços de rede | Navegador inicia e trava | Inicie com --password-store=basic (extensão browser já faz internamente; se iniciar chromium manualmente, lembre de usar) |
| Bloqueio de instância única do soffice | Se LibreOffice já estiver aberto, open para documento similar pode não abrir janela ou travar | Primeiro verifique o status do processo soffice; abertura de documento use app:"libreoffice" que segue semântica de lançador; se houve saída anormal anterior, pode aparecer janela "Document Recovery" (testado em 2026-10-18) – ao listar janelas para confirmar, não confunda com a janela do documento alvo |
| Associação MIME do LibreOffice não confiável | Fedora reconhece fodt como text/xml e abre com editor de texto | open deve sempre usar app:"libreoffice" |
| Aplicativo Qt não aparece no barramento a11y | a11y_list_apps não o vê | O sistema já tem ativação global (QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1 em /etc/environment, persistente após reinício); se ainda não aparecer = aplicativo foi iniciado antes da variável de ambiente ou não é vinculação oficial Qt, reinicie o aplicativo |
| Árvore a11y do Chromium/Electron vazia | dump não retorna conteúdo | ① Inicie com --force-renderer-accessibility (extensão browser já usa por padrão); ② toolkit-accessibility deve estar true antes do aplicativo iniciar (já ativado globalmente; alterar depois não funciona, reinicie o aplicativo); ③ árvore construída lentamente, faça um dump para a ponte acionar (veja disciplina a11y na §2) |
| Escolha da injeção de teclado | Precisa digitar / atalhos de teclado | scripts/kb-inject.sh: texto e combinações de teclas usam wtype (nível de usuário); teclas de controle como Enter/Tab não funcionam com wtype no GTK, use ydotool (sudo); chinês pode perder o primeiro caractere, após digitar leia de volta da árvore a11y para conferir |
| Aquário inicia com overlay de atalhos do niri | Screenshot fica coberto por "Important Hotkeys" | Injete Esc para fechar; o sandbox do agente não consegue conectar ao socket do ydotoold (root 600), use niri__open_app para executar a injeção no ambiente real do desktop |
| Desvio do ponteiro do ydotool | Posicionamento absoluto impreciso (aceleração libinput ≈0.5) | Não confie no ponteiro; injeção de teclado é confiável; diferença de caminho do socket /tmp/.ydotool_socket vs $XDG_RUNTIME_DIR |
| Árvore inicial do GTK4 incompleta | dump retorna apenas dezenas de nós | Primeiro faça a11y_list_apps/dump uma vez para o cliente AT se registrar, depois o dump fica completo (testado: 16 → 105 nós) |
| Confirmação T1/T2 em execução headless | 30s/300s sem resposta nega automaticamente | Comportamento esperado: operações de escrita requerem presença do usuário, ou durante testes responda programaticamente via org.agentos.Confirm1.Respond |
| Instalação de pacote bloqueada por packagekitd | dnf falha ocasionalmente | Antes de instalar: systemctl stop packagekit (helper T2 já trata isso) |
5. Caminho de Upgrade (quando o aplicativo alvo não abrir, tente nesta ordem)
L0 (camada de sistema, sempre tente primeiro) → L1 (a11y: GTK3/4/Qt já acessíveis por padrão; Chromium verifique flag e ordem do
toolkit-accessibility; Electron de terceiros adicione flag conforme apêndice B do capabilities.md) →
L2 (páginas web obrigatoriamente) → L3 fallback (grim para ver + kb-inject para teclado; ponteiro não confiável).
Tipos que ainda não abrem: aplicativos puramente X11 (classe xterm, sem árvore, L3 é o fim);
Java (requer JAB, caminho no apêndice B do capabilities.md); UI do próprio compositor - apenas injeção de entrada.
Tabela detalhada no repositório docs/capabilities.md.